poj 1636 Prison rearrangement

博客探讨了如何解决POJ 1636编程挑战,涉及监狱中人员排列重组的问题。通过动态规划的方法,文章分析了如何确定两个监狱人员能进行交换的条件,并利用DFS建立相关联的物体。博主提供了关键的dp状态转移方程,即dp[i][j] = dp[i][j] | dp[i - x][j - y],帮助理解解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目传送门

Prison rearrangement
Time Limit: 3000MS Memory Limit: 10000K
Total Submissions: 2692 Accepted: 1171

Description

In order to lower the risk of riots and escape attempts, the boards of two nearby prisons of equal prisoner capacity, have decided to rearrange their prisoners among themselves. They want to exchange half of the prisoners of one prison, for half of the prisoners of the other. However, from the archived information of the prisoners' crime history, they know that some pairs of prisoners are dangerous to keep in the same prison, and that is why they are separated today, i.e. for every such pair of prisoners, one prisoners serves time in the first prison, and the other in the second one. The boards agree on the importance of keeping these pairs split between the prisons, which makes their rearrangement task a bit tricky. In fact, they soon find out that sometimes it is impossible to fulfil their wish of swapping half of the prisoners. Whenever this is the case, they have to settle for exchanging as close to one half of the prisoners as possible.

Input

On the first line of the input is a single positive integer n, telling the number of test scenarios to follow. Each scenario begins with a line containing two non-negative integers m and r, 1 < m < 200 being the number of prisoners in each of the two prisons, and r the number of dangerous pairs among the prisoners. Then follow r lines each containing a pair xi yi of integers in the range 1 to m,which means that prisoner xi of the first prison must not be placed in the same prison as prisoner yi of the second prison.

Output

For each test scenario, output one line containing the largest integer k <= m/2 , such that it is possible to exchange k prisoners of the first prison for k prisoners of the second prison without getting two prisoners of any dangerous pair in the same prison.

Sample Input

3
101 0
3 3
1 2
1 3
1 1
8 12
1 1
1 2
1 3
1 4
2 5
3 5
4 5
5 5
6 6
7 6
8 7
8 8

Sample Output

50
0
3

Source


题解

很显然我们会发现当我们要移动某一个人时,与他有关的人也会移动。因此我们可以将这些人当作一个物体。我们设定dp[i][j]表示第一个监狱i个人与第二个监狱j个人能否交换。不难得出dp[i][j] = dp[i][j] | dp[i - x][j - y](x,y为处于同一物体的第一第二监狱人数)。至于建立物体则直接用dfs。

#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;

bool dp[103][103], vis[2][203];
vector<int>edge[2][203];
int Siz[2];

void dfs(int Belong, int u) {
	vis[Belong][u] = 1; ++Siz[Belong];
	for (int i = 0; i < edge[Belong][u].size(); ++i)
		if (!vis[Belong^1][edge[Belong][u][i]]) dfs(Belong ^ 1, edge[Belong][u][i]);
}

void Search(int Belong, int n) {
	for (int i = 1; i <= n; ++i)
		if (!vis[Belong][i]) {
			memset(Siz, 0, sizeof Siz);
			dfs(Belong, i);
			for (int x = n >> 1; x >= Siz[0]; --x)
				for (int y = n >> 1; y >= Siz[1]; --y)
					dp[x][y] |= dp[x - Siz[0]][y - Siz[1]];
		}
}

int main() {
	int T, n, k, a, b;
	scanf("%d", &T);
	while (T--) {
		scanf("%d%d", &n, &k);
		memset(dp, 0, sizeof dp); dp[0][0] = true;
		memset(vis, 0, sizeof vis);
		for (int i = 1; i <= n; ++i) 
			edge[0][i].clear(), edge[1][i].clear();
		for (int i = 1; i <= k; ++i) {
			scanf("%d%d", &a, &b);
			edge[0][a].push_back(b); edge[1][b].push_back(a);
		}
		Search(0, n); Search(1, n);
		for (int i = n >> 1; ~i; --i)
			if (dp[i][i]) {
				printf("%d\n", i); break;
			}
	}
	return 0;
}


评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值