题目链接:http://poj.org/problem?id=1417
大致题意:有两类人,好人和坏人,好人只会说真话,坏人只会说假话,有k组询问,p1个好人,p2个坏人。每组向a询问b是否为好人,得到答复yes或no。问通过已知询问是否能够判断出所有的好人。若不能输出"no",可以则输出代表好人的编号。
在看了博客文章之后才有比较清晰的思路,感觉自己对综合性稍强的题目就已经没什么办法了,还需要学习
思路:利用带权并查集,将所有人分组。如果回答为yes则无论如何a与b均为同一类人,否则不同类。分类后,遍历每一类人,用背包求出能够组合出p1人的方案数量。如果数量不为1则说明没有确定所有的好人。否则则可以求出所有好人的编号。以每组人数为路径标识按路径将每组人的编号求出来。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 605;
int k,p1,p2,n;
int fa[N],offset[N];
int num[N][4];
bool vis[N];
int dp[N][N];
int path[N][N];
vector<int> vec[N][4];
void init()
{
for (int i=0;i<N;i++)
{
fa[i] = i;
offset[i] = 0;
}
memset(dp,0,sizeof (dp));
memset(vis,false,sizeof (vis));
}
int fnd(int x)
{
if (x!=fa[x])
{
int t = fa[x];
fa[x] = fnd(fa[x]);
offset[x] = (offset[x] + offset[t])%2;
}
return fa[x];
}
void read()
{
int ofst;
int x,y;
char re[20];
scanf("%d%d%s",&x,&y,&re);
if (re[0] == 'y')
ofst = 0;
else ofst = 1;
int fx = fnd(x);
int fy = fnd(y);
if (fx!=fy)
{
fa[fx] = fy;
offset[fx] = (offset[y] + ofst - offset[x] + 2)%2;
}
}
int main()
{
while (scanf("%d%d%d",&k,&p1,&p2)==3)
{
init();
if (k==0 && p1==0 && p2==0) break;
n = p1 + p2;
for (int i=0;i<k;i++)
{
read();
}
for (int i=0;i<N;i++)
{
num[i][0] = 0;
num[i][1] = 0;
vec[i][1].clear();
vec[i][0].clear();
}
int cnt = 1;
for (int i=1;i<=n;i++)
{
if (!vis[i])
{
int t = fnd(i);
for (int j=i;j<=p1+p2;j++)
{
if (fnd(j)==t)
{
vis[j] = true;
num[cnt][offset[j]]++;
vec[cnt][offset[j]].push_back(j);
}
}
cnt++;
}
}
dp[0][0] = 1;
for (int i=1;i<cnt;i++)
{
for (int j=p1;j>=0;j--)
{
if (j>=num[i][0] && dp[i-1][j - num[i][0]])
{
dp[i][j] += dp[i-1][j - num[i][0]];
path[i][j] = j - num[i][0];
}
if (j>=num[i][1] && dp[i-1][j - num[i][1]])
{
dp[i][j] += dp[i-1][j - num[i][1]];
path[i][j] = j - num[i][1];
}
}
}
vector<int> ans;
if (dp[cnt-1][p1]!=1) printf("no\n");
else
{
ans.clear();
int t = p1;
for (int i=cnt-1; i>=0; i--)
{
int tmp = t - path[i][t];
if (tmp == num[i][0])
{
int len = vec[i][0].size();
for (int pos=0; pos<len; pos++)
{
ans.push_back(vec[i][0][pos]);
}
}
else
{
int len = vec[i][1].size();
for (int pos=0; pos<len; pos++)
{
ans.push_back(vec[i][1][pos]);
}
}
t = path[i][t];
}
sort(ans.begin(),ans.end());
int len = ans.size();
for (int i=0;i<len;i++)
printf("%d\n",ans[i]);
printf("end\n");
}
}
return 0;
}