POJ1636 Prison rearrangement(背包、并查集)

题目链接:

  http://poj.org/problem?id=1636

题目描述:

Prison rearrangement
 

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

 

题目大意:

  两个监狱交换等数量的犯人(不超过一半),有的犯人不能在一个监狱,求最大交换人数

思路:

  考虑有关系的人必须要全交换或者不交换,于是用并查集缩点,最后是一组数对的形式,每个数对表示有关系的两个监狱的人数

  然后 dp[ i ][ j ] 表示是否存在A监狱中 i 个人和B监狱中 j 个人可交换

  背包求解,最后看 dp[ i ][ i ] = true 的最大 i 即为答案

 

代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <vector>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 const int N = 420;
 9 
10 struct P {
11     int a, b;
12     P(int a = 0, int b = 0) :a(a), b(b) {}
13 };
14 
15 
16 int m, r, pre[N], cnt1[N], cnt2[N];
17 vector<P> ve;
18 
19 int find(int a) { return a == pre[a] ? a : pre[a] = find(pre[a]); }
20 
21 void merge(int a, int b) {
22     int ra = find(a), rb = find(b);
23     if (ra != rb)pre[ra] = rb;
24 }
25 
26 void init() {
27     for (int i = 1; i <= 2 * m; ++i)pre[i] = i;
28     memset(cnt1, 0, sizeof(cnt1));
29     memset(cnt2, 0, sizeof(cnt2));
30     ve.clear();
31 }
32 
33 int main() {
34     int t, a, b;
35     scanf("%d", &t);
36     while (t--) {
37         scanf("%d%d", &m, &r);
38         init();
39         for (int i = 0; i < r; ++i) {
40             scanf("%d%d", &a, &b);
41             merge(a, b + m);
42         }
43         for (int i = 1; i <= m; ++i)++cnt1[find(i)];
44         for (int i = m + 1; i <= 2 * m; ++i)++cnt2[find(i)];
45         for (int i = 1; i <= 2 * m; ++i) if (cnt1[i] || cnt2[i])
46             ve.push_back(P(cnt1[i], cnt2[i]));
47         int mm = (m >> 1);
48         bool dp[N][N] = { 0 };
49         dp[0][0] = 1;
50         for (int i = 0; i < (int)ve.size(); ++i)
51             for (int j = mm; j >= ve[i].a; --j)
52                 for (int k = mm; k >= ve[i].b; --k)
53                     if (dp[j - ve[i].a][k - ve[i].b])dp[j][k] = true;
54         int ans = mm;
55         while (!dp[ans][ans])--ans;
56         printf("%d\n", ans);
57     }
58 }

 

posted @ 2017-07-12 14:30  hyp1231  阅读(679)  评论(0编辑  收藏  举报