标签:
Description
Input
Output
Sample Input
2 1 1 1 2 no 2 1 no 3 2 1 1 1 yes 2 2 yes 3 3 yes 2 2 1 1 2 yes 2 3 no 5 4 3 1 2 yes 1 3 no 4 5 yes 5 6 yes 6 7 no 0 0 0
Sample Output
no no 1 2 end 3 4 5 6 end
Source
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <vector> 6 #include <utility> 7 #include <iomanip> 8 #include <string> 9 #include <cmath> 10 #include <queue> 11 #include <map> 12 #define LOCAL 13 const int MAXN = 1000 + 10; 14 const int MAX = 30000 + 10; 15 using namespace std; 16 struct DATA{ 17 int a, b; 18 }data[MAXN]; 19 int n, p1, p2, q; 20 int parent[MAXN] ,val[MAXN]; 21 int num[MAXN];//num[i]代表如果i是并查集中的根,那么他在AB表中的位置就num[i] 22 int f[MAXN][MAXN], cnt; 23 int pre[MAXN][MAXN];//DP中记录状态转移过来的位置 24 int Ans[MAXN];//表示答案中被选为好人或者不是好人 25 26 int find(int x){ 27 int f = x, tmp = 0; 28 while (x != parent[x]){ 29 tmp += val[x]; 30 x = parent[x]; 31 } 32 parent[f] = x; 33 val[f] = tmp % 2; 34 return x; 35 } 36 37 void init(){ 38 n = p1 + p2;//即总的人数 39 //val为0代表相同集合,1代表不同的集合 40 for (int i = 1; i <= n; i++){ 41 val[i] = 0; 42 parent[i] = i; 43 } 44 for (int i = 1; i <= q; i++){ 45 int x, y; 46 char str[5]; 47 scanf("%d%d", &x, &y); 48 scanf("%s", str); 49 if (find(x) == find(y)) continue;//在同一个集合之内就不用考虑了 50 else{ 51 if (str[0] == ‘y‘){ //一定是一种集合之内 52 int xx = find(x), yy = find(y); 53 parent[xx] = y; 54 val[xx] = (-val[x] + 2) % 2; 55 }else{ 56 int xx = find(x), yy = find(y); 57 parent[xx] = y; 58 val[xx] = (-val[x] + 3) % 2; 59 } 60 } 61 } 62 } 63 //计算出各个并查集的同类和不同类 64 void prepare(){ 65 memset(data, 0, sizeof(data)); 66 cnt = 0; 67 for (int i = 1; i <= n; i++){ 68 if (parent[i] != i) continue; 69 num[i] = ++cnt; 70 } 71 for (int i = 1; i <= n; i++){ 72 int xx = find(i); 73 if (val[i] == 0) data[num[xx]].a++;//和它同一类 74 else data[num[xx]].b++;//不同类 75 } 76 } 77 void dp(){ 78 memset(f, 0, sizeof(f)); 79 //f[i][j]表示到了第i个好人有j个的时候的方案数量,注意只要保存3个量就可以了 80 f[0][0] = 1; 81 for (int i = 1; i <= cnt; i++) 82 for (int j = p1; j >=0; j--){ 83 if (j - data[1].a >= 0) f[i][j] += f[i - 1][j - data[i].a]; 84 if (j - data[1].b >= 0) f[i][j] += f[i - 1][j - data[i].b]; 85 if (f[i][j] >= 2) f[i][j] = 2;//不要做太大了 86 if (f[i][j] == 1){//有解 87 if (j - data[i].a >= 0 && f[i - 1][j - data[i].a] == 1) pre[i][j] = 0;//a类选为好人 88 if (j - data[i].b >= 0 && f[i - 1][j - data[i].b] == 1) pre[i][j] = 1;//b类选为好人 89 } 90 } 91 if (f[cnt][p1] != 1){printf("no\n");return;} 92 int last = p1; 93 for (int i = cnt; i >= 1; i--){ 94 Ans[i] = pre[i][last]; 95 if (Ans[i] == 0) last -= data[i].a; 96 else last -= data[i].b; 97 } 98 for (int i = 1; i <= n; i++){ 99 int xx = find(i); 100 if (Ans[num[xx]] == 1 && val[i] == 1) printf("%d\n", i); 101 if (Ans[num[xx]] == 0 && val[i] == 0) printf("%d\n", i); 102 } 103 printf("end\n"); 104 } 105 106 int main(){ 107 int T; 108 #ifdef LOCAL 109 freopen("data.txt", "r", stdin); 110 freopen("out.txt", "w", stdout); 111 #endif 112 while (scanf("%d%d%d", &q, &p1, &p2)){ 113 if (q == 0 && p1 == 0 && p2 == 0) break; 114 init(); 115 prepare(); 116 dp(); 117 //printf("%d", data[1].b); 118 } 119 return 0; 120 }
【POJ1417】【带标记并查集+DP】True Liars
标签:
原文地址:http://www.cnblogs.com/hoskey/p/4322051.html