POJ 1636 Prison rearrangement

Prison rearrangement
Time Limit: 3000MS   Memory Limit: 10000K
Total Submissions: 1447   Accepted: 693

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

Northwestern Europe 2003

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAXN 210

struct LEdge{
	int ed, next;
}edge[MAXN * MAXN];
int head[2 * MAXN], nEdge;

void init(){
	nEdge = 0;
	memset(head, 0xff, sizeof(head));
}

void addEdge(int i, int j){
	edge[nEdge].ed = j;
	edge[nEdge].next = head[i];
	head[i] = nEdge++;
}

int f[MAXN][MAXN];
int vis[MAXN][2];

int m, r;
int np, nq;
void dfs(int cur, int flag){
	int i;
	if (!flag) np++;
	else nq++;
	vis[cur][flag] = 1;
	for (i = head[2 * cur + flag]; i != -1; i = edge[i].next){
		if (vis[edge[i].ed / 2][1 - flag]) continue;
		dfs(edge[i].ed / 2, 1 - flag);
	}
}

void dp(int np, int nq){
	int j, k;
	for (j = m / 2; j >= 0; j--){
		for (k = m / 2; k >= 0; k--){
			if (j - np >= 0 && k - nq >= 0){
				f[j][k] |= f[j - np][k - nq];
			}
		}
	}
}

int main(){
	int i, j, k, T;
	scanf("%d", &T);
	while(T--){
		init();
		scanf("%d%d", &m, &r);
		for (k = 0; k < r; k++){
			scanf("%d%d", &i, &j);
			addEdge(2 * i, 2 * j + 1);
			addEdge(2 * j + 1, 2 * i);
		}
		memset(vis, 0, sizeof(vis));
		memset(f, 0, sizeof(f));
		f[0][0] = 1;
		for (i = 1; i <= m; i++){
			if (!vis[i][0]){
				np = nq = 0;
				dfs(i, 0);
//				printf("i = %d, flag = %d, np = %d, nq = %d\n", i, 0, np, nq);
				dp(np, nq);
			}
			if (!vis[i][1]){
				np = nq = 0;
				dfs(i, 1);
//				printf("i = %d, flag = %d, np = %d, nq = %d\n", i, 1, np, nq);
				dp(np, nq);
			}
			if (f[m / 2][m / 2]) break;
		}
		for (i = m / 2; i >= 0; i--)
			if (f[i][i]) break;
		printf("%d\n", i);
	}
	return 0;
}
/*
开始看样例的时候注意到了,但是写的时候却忽略了,尤其在邻接表建边的时候,读进来直接就往里加边...
因为这个WA了一次,感觉没有坑,过了样例就行

简述下算法
预处理,将人分成互相有影响的几个集合,集合内的人要走就必须全部走。把集合看做一个属性为(p,q)的物品(表示prison1中有p人,prison2中有q人)放到背包(m/2,m/2)中
当然,无影响的人就是(1,0)或(0,1)
然后,普通的可行性背包

开始想到了背包,但是纠结于怎么表达一个人影响其他许多人,总觉得用图表示什么的...
没想到预处理下就好了...
*/


你可能感兴趣的:(Integer,input,each,Exchange,output,pair)