您的位置:首页 > 产品设计 > UI/UE

POJ 1417 True Liars

2013-08-05 11:28 330 查看
题意:有p个好人,q个坏人,他们说了n句话,格式为A说B是好/坏人

坏人全说谎话,好人全说真话,问你能不能知道他们中全部的好人是谁。

解法:划分好人为一类,坏人为一类,简单分析可得,同类会对同类说yes,对非同类说no。所以通过并查集就可以知道每个集合内的划分关系。

由于题目给出的关系可能描述不同的集合,那么你就需要把这些集合拼凑在一起,看能不能仅得到一种构成p个人的组合。

因为可能的集合数有600种,暴力搜索规模有2^600次,显然超时,所以考虑DP。设状态DP[I][J]为已选择了i个集合共选j个人有几种方法。(其实就是个分组背包,每个组的物品限制只能且必选一样)

则若能只得到一种组合方法,DP[TOT][P]的值必须为1。

题目还要求升序打印好人的id,那么从最后的状态逆推回去就可以了。

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;

const int INF = ~0u>>1;
typedef pair<int,int> P;
#define REP(i,a,b) for(int i=(a); i<(b); i++)
#define FOR(i,a,b) for(int i=(a); i<=(b); i++)
#define FORP(i,a,b) for(int i=(a); i>=(b); i--)
#define clr(a,b) memset(a,b,sizeof(a))
#define PB push_back

const int MAXN = 610;
int fa[MAXN];
int rel[MAXN];
int n,p,q;
int sum;

int Find(int x) {
if(x == fa[x]) return x;
int ff = fa[x];
fa[x] = Find(fa[x]);
rel[x] = (rel[x] + rel[ff]) % 2;
return fa[x];
}

void merge(int a, int b, int op) {
int aa = Find(a);
int bb = Find(b);
if(aa == bb) return ;
fa[aa] = bb;
rel[aa] = (rel[b]-rel[a]+op+2)%2;
}

vector <int> cr[MAXN][2];
vector <int> :: iterator it;
map <int,int> ss;
int dp[MAXN][MAXN];
int ans[MAXN],cnt;

int gao() {
int tot = 0;
ss.clear();
FOR(i,1,sum) FOR(j,0,1) cr[i][j].clear();
FOR(i,1,sum) {
Find(i);
if(ss.count(fa[i]) == 0)
ss.insert(P(fa[i],++tot));
cr[ss[fa[i]]][rel[i]].PB(i);
}

clr(dp,0);
dp[0][0] = 1;
FOR(i,1,tot) {
FOR(j,0,1) {
int x = cr[i][j].size();
//          printf("i = %d, j = %d, x = %d\n", i,j,x);
FOR(k,0,p-x) {
dp[i][k+x] += dp[i-1][k];
}
}
}
/*   FOR(i,0,tot) {
FOR(j,0,p) printf("%d ", dp[i][j]);
printf("\n");
}*/
if(dp[tot][p] != 1) return 0;
cnt = 0;
int pos = p;
FORP(i,tot,1) {
FOR(j,0,1) {
int x = cr[i][j].size();
if(dp[i-1][pos-x] == 1) {
//          printf("pos = %d, pos-x = %d\n", pos,pos-x);
//            printf("ok : %d %d %d\n", i,j,x);
for(it=cr[i][j].begin();it!=cr[i][j].end(); it++) {
ans[cnt++] = *it;
}
pos -= x;
//              printf("cnt = %d\n", cnt);
break;
}
}
}
sort(ans,ans+cnt);
REP(i,0,cnt) printf("%d\n", ans[i]);
return 1;
}

int main() {
while(~scanf("%d%d%d", &n, &p, &q), n||p||q) {
sum = p+q;
FOR(i,1,p+q) fa[i] = i;
int a, b;
char s[5];
clr(rel,0);
while(n--) {
scanf("%d%d%s", &a, &b, s);
merge(a,b,s[0]!='y');
}
if(p == q) {
printf("no\n");
}
else {
if(!gao()) printf("no\n");
else printf("end\n");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: