考虑2-sat。然后发现建图会发生一些有趣的事情
如果A说了一句C,说是B是好人,那么可以建成下面这个图(以下两张图请自行把右下角的A'看成B'):
如果A说了一句C,说是B是坏人,那么可以建成下面这个图:
两个图中,连的边都是无向边,然后发现每句话不用建点,直接可以省去。每句话可以看成告诉你两个人是不是同一部落的。
因为图太简单了,然后就不用2-sat了,直接上带权并查集维护点之间的相等和不等关系。
然后可以得到若干个对立的联通块。如果一个块是好人块,那么对立的块就是坏人块。
然后可以做一遍背包。这道题就水完了。
当然,这道题完全可以不用并查集。直接建图,对于未被访问的点从它开始搜索,可以找出所有和它是同一部落的人,这个连通块剩下的就是在不同部落的人。
Code
1 /** 2 * poj 3 * Problem#1417 4 * Accepted 5 * Time: 16ms 6 * Memory: 1348k 7 */ 8 #include <iostream> 9 #include <cstdlib> 10 #include <cstring> 11 #include <cstdio> 12 using namespace std; 13 typedef bool boolean; 14 15 const int N = 1005; 16 17 int n, nperson; 18 int divine, devilish; 19 int uf[N], relation[N]; 20 int f[N][305]; 21 int size[N][2]; 22 char str[10]; 23 24 int find(int x) { 25 if (uf[x] == x) 26 return x; 27 int next_father = find(uf[x]); 28 relation[x] ^= relation[uf[x]]; 29 return uf[x] = next_father; 30 } 31 32 inline boolean init() { 33 scanf("%d%d%d", &n, &divine, &devilish); 34 if (!n && !divine && !devilish) 35 return false; 36 nperson = divine + devilish; 37 for (int i = 1; i <= nperson; i++) 38 uf[i] = i, relation[i] = 0; 39 for (int i = 1, u, v; i <= n; i++) { 40 scanf("%d%d%s", &u, &v, str); 41 int newr = (str[0] == 'n'); 42 if (find(u) != find(v)) { 43 relation[uf[u]] = relation[u] ^ newr; 44 uf[uf[u]] = v; 45 } 46 } 47 return true; 48 } 49 50 inline void solve() { 51 for (int i = 1; i <= nperson; i++) 52 size[i][0] = size[i][1] = 0; 53 for (int i = 1; i <= nperson; i++) 54 if (find(i) == i) 55 size[i][0]++; 56 else 57 size[find(i)][relation[i]]++; 58 int ls = 0; 59 memset(f, 0, sizeof(f)); 60 f[0][0] = 1; 61 for (int i = 1; i <= nperson; i++) 62 if (find(i) == i) { 63 for (int j = size[i][0]; j <= divine; j++) 64 f[i][j] = min(2, f[i][j] + f[ls][j - size[i][0]]); 65 for (int j = size[i][1]; j <= divine; j++) 66 f[i][j] = min(2, f[i][j] + f[ls][j - size[i][1]]); 67 ls = i; 68 } 69 70 if (f[ls][divine] != 1) 71 puts("no"); 72 else { 73 int rest = divine; 74 for (int i = ls - 1; ~i; i--) { 75 if (find(i) == i) { 76 if (size[ls][0] <= rest && f[i][rest - size[ls][0]]) 77 rest -= size[ls][0], size[ls][0] = -1; 78 else 79 rest -= size[ls][1], size[ls][1] = -1; 80 ls = i; 81 } 82 } 83 84 for (int i = 1; i <= nperson; i++) 85 if (size[find(i)][relation[i]] == -1) 86 printf("%d\n", i); 87 puts("end"); 88 } 89 } 90 91 int main() { 92 while (init()) 93 solve(); 94 return 0; 95 }