POJ-1636 二維DP
阿新 • • 發佈:2018-12-23
狀態轉換方程:dp[k][i][j] = dp[k-1][i-a[k]][j-b[k]] || dp[k-1][i][j]。簡單解釋一下:dp[k][i][j]表示對前K組,用監獄A的i個人和監獄B的j個人交換是否成功。前K組的解與前K-1組有關。當前K-1組解決後,只要加上第K組就可以搞定前K組。對第K組有兩種選擇:選或不選。
DFS code:
#include<iostream> #include<cstdio> #include<algorithm> #include<string> #include<cstring> #define N 205 using namespace std; int t; int n, m; int anum, bnum; int map[N][N]; int dp[N][N]; int vis[2][N]; void DFS(int side, int t) { vis[side][t] = 1; if (side == 0) { anum++; for (int i = 1; i <= n; i++) { if (map[t][i] && !vis[1][i]) { DFS(1, i); } } } else { bnum++; for (int i = 1; i <= n; i++) { if (map[i][t] && !vis[0][i]) { DFS(0, i); } } } } int main() { scanf("%d", &t); while (t--) { memset(map, 0, sizeof(map)); memset(dp, 0, sizeof(dp)); memset(vis, 0, sizeof(vis)); scanf("%d%d", &n, &m); for (int i = 0; i < m; i++) { int x, y; scanf("%d%d", &x, &y); map[x][y] = 1; } int a[N], b[N]; int k = 0; for (int i = 1; i <= n; i++) { if (vis[0][i])continue; anum = 0; bnum = 0; DFS(0, i); a[k] = anum; b[k++] = bnum; } for (int i = 1; i <= n; i++) { if (vis[1][i])continue; anum = 0; bnum = 0; DFS(1, i); a[k] = anum; b[k++] = bnum; } dp[0][0] = 1; for (int i = 0; i < k; i++) { for (int j = n / 2; j >= a[i]; j--) { for (int h = n / 2; h >= b[i]; h--) { if (dp[j][h]||dp[j - a[i]][h - b[i]] == 1) { dp[j][h] = 1; } } } } for (int i = n / 2; i >= 0; i--) { if (dp[i][i] == 1) { cout << i << endl; break; } } } }
並查集 code:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<set>p #define N 205 using namespace std; int t; int p[2*N]; int find(int x) { if (x != p[x]) { p[x] = find(p[x]); } else return x; } void build(int x, int y) { int xx = find(x); int yy = find(y); if (xx != yy) { p[xx] = yy; } } void init(int n) { for (int i = 1; i <= 2 * n; i++) { p[i] = i; } } int main() { int x, y, n, ks; scanf("%d", &t); while (t--) { int a[N]; int b[N]; int sum[2 * N]; int dp[N / 2][N / 2]; memset(dp, 0, sizeof(dp)); dp[0][0] = 1; memset(a, 0, sizeof(a)); memset(sum, 0, sizeof(sum)); memset(b, 0, sizeof(b)); scanf("%d%d", &n, &ks); init(n); for (int i = 0; i < ks; i++) { scanf("%d%d", &x, &y); build(x, y + n); } int ans = 1; for (int i = 1; i <= n; i++) { int x = find(i); if (sum[x] == 0) { sum[x] = ans++; a[sum[x]]++; } else { a[sum[x]]++; } } for (int i = n + 1; i <= 2 * n; i++) { int x = find(i); if (sum[x] == 0) { sum[x] = ans++; b[sum[x]]++; } else { b[sum[x]]++; } } for (int i = 1; i < ans; i++) { for (int j = n / 2; j >= a[i]; j--) { for (int k = n / 2; k >= b[i]; k--) { if (dp[j][k]||dp[j - a[i]][k - b[i]] == 1) { dp[j][k] = 1; } } } } for (int i = n / 2; i >= 0; i--) { if (dp[i][i] == 1) { cout << i << endl; break; } } } return 0; }