题目链接:http://poj.org/problem?id=1636
题目大意及思路:两个监狱交换囚犯,但有些囚犯不能在同一个监狱,问最接近m/2的交换数,做法是先求连通分量和两个监狱分别的人数,没有关联的人则为(0,1)和(1,0);最后dp,求得最接近m/2的i 满足dp[i][i]=1。
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<string> #include<queue> #include<algorithm> #include<vector> #include<stack> #include<list> #include<iostream> #include<map> using namespace std; #define inf 0x3f3f3f3f #define Max 110 int max(int a,int b) { return a>b?a:b; } int min(int a,int b) { return a<b?a:b; } struct node { int next,to; }e[2*210*210]; int cnt; int num1[210],num2[210],num[210],eid,p[410],vst[410],dp[210][210]; int t,n,m; inline void addedge(int u,int v) { e[eid].to=v; e[eid].next=p[u]; p[u]=eid++; } void dfs(int u) { int i,v; vst[u]=1; if(u<=m) num1[cnt]++; else num2[cnt]++; for(i=p[u];i!=-1;i=e[i].next) { v=e[i].to; if(vst[v]) continue; dfs(v); } } int main() { int i,j,k,u,v; scanf("%d",&t); while(t--) { scanf("%d%d",&m,&n); eid=0,cnt=1; memset(p,-1,sizeof(p)); memset(vst,0,sizeof(vst)); memset(dp,0,sizeof(dp)); // memset(num,0,sizeof(num)); memset(num1,0,sizeof(num1)); memset(num2,0,sizeof(num2)); while(n--) { scanf("%d%d",&u,&v); addedge(u,v+m); addedge(v+m,u); } int rec=0; for(i=1;i<=2*m;i++) { if(!vst[i]) { // printf("i %d\n",i); dfs(i); // num[cnt]=max(num1[cnt],num2[cnt]); cnt++; } } dp[0][0]=1; for(i=1;i<cnt;i++) { // printf("i %d num %d\n",i,num[i]); for(j=m/2;j>=0;j--) { for(k=m/2;k>=0;k--) { if(j-num1[i]>=0&&k-num2[i]>=0&&dp[j-num1[i]][k-num2[i]]) dp[j][k]=1; } } } for(j=m/2;j>=0;j--) { if(dp[j][j]) { printf("%d\n",j); break; } } } }