题目大意:给出两侧分别有m个节点的图,边不可能存在于同一侧的点之间.从左和右侧分别挑出数量相等且不大于m/2个一些点,进行交换,使换完后不存在同一侧的边。求最大交换点的数。。
思路:进行联通二分图染色。。颜色相同的点必须同时交换。。不然就有边处于同一测。。
然后dp
f[i][j]表示一个交换i个,一个个交换j个是否可行
f[i][j] =f[i - vx[k]][j - vy[k]]|| f[i-vy[k]][j - vx[k]];
vx[k],vy[k]表示联通块的相同颜色的个数
1 /* 2 Time:2013-03-07 00:50:09 3 State:Accepted 4 */ 5 #include <iostream> 6 #include <cstring> 7 #include <string> 8 #include <cstdlib> 9 #include <cstdio> 10 #include <vector> 11 #include <cmath> 12 #include <algorithm> 13 #define CLR(NAME) memset(NAME , 0 ,sizeof(NAME)) 14 using namespace std; 15 int test , m ,r , e[410][210] , sum[3] ,vx[210] ,vy[210] , bo[410] ,tot , f[210][210]; 16 void init(){ 17 int x , y ; 18 scanf("%d%d",&m ,&r); 19 CLR(e); CLR(f); 20 CLR(bo); CLR(vx); CLR(vy); 21 for (int i = 1 ; i <= r; ++i){ 22 scanf("%d%d", &x ,&y); 23 y += 200; 24 ++e[x][0]; 25 ++e[y][0]; 26 e[x][e[x][0]] = y; 27 e[y][e[y][0]] = x; 28 } 29 } 30 31 void dfs(int node){ 32 if (bo[node]) return; 33 bo[node] = 1; 34 if (node <= 200) ++sum[0]; 35 else ++sum[1]; 36 for (int i = 1; i <= e[node][0]; ++i) 37 dfs(e[node][i]); 38 } 39 40 void solve(){ 41 tot = 0; 42 for (int i = 1; i <= m; ++i ) 43 if (!bo[i]){ 44 sum[0] = sum[1] = 0; 45 dfs(i); 46 vx[++ tot] = sum[0]; 47 vy[tot] = sum[1]; 48 } 49 for (int i = 201; i <= m + 200; ++i) 50 if (!bo[i]){ 51 sum[0] = sum[1] = 0; 52 dfs(i); 53 vx[++ tot] = sum[0]; 54 vy[tot] = sum[1]; 55 } 56 57 58 59 f[0][0] = 1; 60 61 for (int k = 1; k <= tot; ++k) 62 for (int i = m / 2 ; i >= vx[k] ; --i) 63 for (int j = m / 2 ; j >= vy[k]; --j) 64 f[i][j] = f[i][j] | f[i - vx[k]][j - vy[k]]; 65 66 for (int i = m / 2 ; i >= 0; --i) 67 if (f[i][i]){ 68 printf("%d\n",i); 69 return; 70 } 71 72 73 74 } 75 76 int main(){ 77 freopen("poj1636.in","r",stdin); 78 freopen("poj1636.out","w",stdout); 79 scanf("%d",&test); 80 for (int i = 1; i <= test ; ++i){ 81 init(); 82 solve(); 83 } 84 fclose(stdin); fclose(stdout); 85 }