码迷,mamicode.com
首页 > 其他好文 > 详细

POJ1636 动态规划+并查集

时间:2014-07-21 00:06:04      阅读:327      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   os   io   

 POJ1636

问题重述:

两个监狱中各有m个囚犯,欲对这两个监狱中的囚犯进行等数量的交换。已知某些囚犯不能关押在同一个监狱,求解可以交换人数的最大值k (k < m/2)。

 

分析:

假设监狱1中的囚犯a与监狱2中的囚犯b不能共存。那么假如对a进行交换,也必须对b进行交换。因此,根据互斥关系建立的连通集两边的成员必须同时进行交换。

 

求解步骤:

1)  根据已知的互斥关系,采用并查集建立连通集,分别记录每个连通集在两个监狱中的成员数目,记为v1, v2。

2)  采用动态规划算法,用布尔变量dp[i][j]表示监狱1中i个囚犯与监狱2中的j个囚犯进行交换的可行性。则有dp[i][j] = dp[i – v1[k]][j – v2[k]]

3)  满足dp[i][i] = 1, i < m/2的i的最大值即所求的解。

  1 //Memory: 580K        Time: 63MS
  2 #include <iostream>
  3 #include <cstring>
  4 #include <cstdio>
  5 
  6 using namespace std;
  7 
  8 const int maxn = 410;
  9 int m, r;
 10 bool g[maxn][maxn];
 11 int f[maxn];
 12 int nl[maxn];
 13 int nr[maxn];
 14 bool vis[maxn];
 15 int v1[maxn], v2[maxn];
 16 int cnt;
 17 bool dp[maxn][maxn];
 18 
 19 void makeset()
 20 {
 21     memset(f, 0, sizeof(f));
 22     memset(nl, 0, sizeof(nl));
 23     memset(nr, 0, sizeof(nr));
 24     for (int i = 1; i <= 2 * m; i++)
 25         f[i] = i;
 26     for (int i = 1; i <= m; i++) {
 27         nl[i] = 1;
 28         nr[i] = 0;
 29     }
 30     for (int i = 1 + m; i <= m * 2; i++) {
 31         nr[i] = 1;
 32         nl[i] = 0;
 33     }
 34 }
 35 
 36 int find(int a) {
 37     if (f[a] == a) return a;
 38     f[a] = find(f[a]);
 39     return f[a];
 40 }
 41 
 42 void uni(int a, int b) {
 43     int sa = find(a);
 44     int sb = find(b);
 45     if (sa != sb) {
 46         f[sa] = sb;
 47         nl[sb] += nl[sa];
 48         nr[sb] += nr[sa];
 49     }
 50 }
 51 
 52 void init()
 53 {
 54     makeset();
 55     for (int i = 1; i <= m; i++) {
 56         for (int j = m + 1; j <= m * 2; j++) if (g[i][j]) {
 57             uni(i, j);
 58         }
 59     }
 60     cnt = 0;
 61     for (int i = 1; i <= m * 2; i++) {
 62         int s = find(i);
 63         if (s == i) {
 64             v1[cnt] = nl[s];
 65             v2[cnt++] = nr[s];
 66         }
 67     }
 68 }
 69 
 70 int main()
 71 {
 72     int cas;
 73     cin >> cas;
 74     while (cas--) {
 75         memset(g, 0, sizeof(g));
 76         scanf("%d%d", &m, &r);
 77         int a, b;
 78         for (int i = 0; i < r; i++) {
 79             scanf("%d%d", &a, &b);
 80             g[a][b + m] = 1;
 81         }
 82         init();
 83 
 84         memset(dp, 0, sizeof(dp));
 85         dp[0][0] = 1;
 86         for (int i = 0; i < cnt; i++) {
 87             for (int j = m/2; j >= 0; j--)  ////此处必须进行倒序循环:每次循环的dp都由上一轮循环后序号较小的dp确定,倒序循环避免提前更新序号较小的dp
 88                 for (int k = m/2; k >= 0; k--) {  //同上
 89                     if (dp[j][k] && j + v1[i] <= m/2 && k + v2[i] <= m/2)
 90                         dp[j + v1[i]][k + v2[i]] = 1;
 91                 }
 92         }
 93         
 94         for (int i = m / 2; i >= 0; i--) {
 95             if (dp[i][i]) {
 96                 cout << i <<endl;
 97                 break;
 98             }
 99         }
100     }
101     return 0;
102 }

POJ1636 动态规划+并查集,布布扣,bubuko.com

POJ1636 动态规划+并查集

标签:style   blog   http   color   os   io   

原文地址:http://www.cnblogs.com/junxie/p/3857351.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!