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,那么从最后的状态逆推回去就可以了。
坏人全说谎话,好人全说真话,问你能不能知道他们中全部的好人是谁。
解法:划分好人为一类,坏人为一类,简单分析可得,同类会对同类说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; }
相关文章推荐
- POJ1417 True Liars (并查集+背包)
- poj 1417 True Liars 带权并查集+母函数dp
- 【POJ】[1417]True Liars
- poj 1417 True Liars
- POJ 1417 True Liars 带权并查集+DP
- POJ 1417 True Liars
- poj 1417 True Liars
- POJ-1417-并查集-True Liars
- POJ - 1417 并查集+背包
- POJ 1417 True Liars(并查集+DP)
- poj 1417 并查集+dp
- POJ1417 True Liars(DP)
- poj-1417 True Liars 并查集+DP
- POJ 1417 True Liars(种类并查集+dp+路径输出)
- poj 1417 - True Liars(并查集+背包)
- POJ 1417 True Liars(路径压缩并查集+DP背包问题)
- POJ 1417 True Liars(并查集+DP)
- 并查集练习---poj 1417 并查集+DP
- F - True Liars POJ 1417(并查集)(DFS)
- POJ 1417 True Liars(并查集+DP)