POJ-1636 二维DP

状态转换方程: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;
}

猜你喜欢

转载自blog.csdn.net/usernamezzz/article/details/83044124
今日推荐