[题目链接]
http://poj.org/problem?id=1417
[算法]
首先,我们发现 :
如果A说B是好人,那么A和B是同一类人,否则A和B不是同一类人
利用这个性质,用并查集维护这些人之间的关系
问题就转化成了有Cnt个集合,每个集合里包含两类人,我们在每个集合里选出一类人,使得最后共有P1个人
背包即可,由于最后要输出哪些是好人,因此,只需判断方案是否唯一,沿着dp数组递推即可
[代码]
#include <algorithm> #include <bitset> #include <cctype> #include <cerrno> #include <clocale> #include <cmath> #include <complex> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <deque> #include <exception> #include <fstream> #include <functional> #include <limits> #include <list> #include <map> #include <iomanip> #include <ios> #include <iosfwd> #include <iostream> #include <istream> #include <ostream> #include <queue> #include <set> #include <sstream> #include <stdexcept> #include <streambuf> #include <string> #include <utility> #include <vector> #include <cwchar> #include <cwctype> #include <stack> #include <limits.h> using namespace std; #define MAXN 1010 #define MAXP 610 int i,j,n,p1,p2,tot,now,x,y; int a[MAXN],b[MAXN],fa[MAXP<<1],d[MAXP<<1],id[MAXP<<1]; char k[MAXN][5]; int dp[MAXP<<1][MAXP]; vector< int > ans; vector< int > p[MAXP<<1][2]; inline int get_root(int x) { if (fa[x] == x) return x; int f = get_root(fa[x]); d[x] = d[x] ^= d[fa[x]]; return fa[x] = f; } int main() { while (scanf("%d%d%d",&n,&p1,&p2) != EOF && (n || p1 || p2)) { for (i = 1; i <= n; i++) scanf("%d%d%s",&a[i],&b[i],&k[i]); for (i = 1; i <= p1 + p2; i++) { fa[i] = i; d[i] = 0; } for (i = 1; i <= n; i++) { x = get_root(a[i]); y = get_root(b[i]); if (strcmp(k[i],"yes") == 0) { fa[x] = y; d[x] = d[a[i]] ^ d[b[i]]; } else { fa[x] = y; d[x] = d[a[i]] ^ d[b[i]] ^ 1; } } tot = 0; memset(id,0,sizeof(id)); for (i = 1; i <= p1 + p2; i++) { p[i][0].clear(); p[i][1].clear(); } for (i = 1; i <= p1 + p2; i++) { x = get_root(i); if (!id[x]) id[x] = ++tot; p[id[x]][d[i]].push_back(i); } memset(dp,0,sizeof(dp)); dp[0][0] = 1; for (i = 1; i <= tot; i++) { for (j = 0; j <= p1 + p2; j++) { if (j - p[i][0].size() >= 0) dp[i][j] += dp[i-1][j-p[i][0].size()]; if (j - p[i][1].size() >= 0) dp[i][j] += dp[i-1][j-p[i][1].size()]; } } if (dp[tot][p1] == 1) { ans.clear(); now = p1; for (i = tot; i >= 1; i--) { if (now - p[i][0].size() >= 0 && dp[i-1][now-p[i][0].size()]) { for (j = 0; j < p[i][0].size(); j++) ans.push_back(p[i][0][j]); now -= p[i][0].size(); } else { for (j = 0; j < p[i][1].size(); j++) ans.push_back(p[i][1][j]); now -= p[i][1].size(); } } sort(ans.begin(),ans.end()); for (i = 0; i < ans.size(); i++) printf("%d ",ans[i]); printf("end "); } else printf("no "); } return 0; }