POJ 1417 True Liars 带权并查集+DP
来源:互联网 发布:淘宝hd ipad历史版本 编辑:程序博客网 时间:2024/05/21 06:46
题目:
http://poj.org/problem?id=1417
题意:
有两种人:好人和坏人,其中好人说的话一定是真的,坏人说的话一定是假的。现在知道好人和坏人的具体个数,又提问了n个问题:x y yes|no,问第x个人,第y个人是好人还是坏人,回答yes或者no。问根据以上能不能判断出哪些人是好人,题目保证不会有矛盾的问答
思路:
可以根据问答把所有人分类,每类又分成两小类:相互矛盾的两小类,相互矛盾的两小类必定有一类是好人一类坏人,但具体哪一类是好人哪一类是坏人并不知道。然后可以就是看能不能从每一类中当且仅当拿出一个小类凑一起,使人数恰好等于好人的人数,且这个方案数只有一种。可以发现,分类用带权并查集实现,后面凑人数用背包记录方案数和路径可以实现。本人的代码写的太挫了,惨不忍睹,不想改了 。。。
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>#include <set>using namespace std;const int N = 700 + 10, INF = 0x3f3f3f3f;int par[N], rnk[N];int w[N][2];int dp[N][N], pre[N][N], p[N], rp[N];void init(int n){ for(int i = 1; i <= n; i++) par[i] = i, rnk[i] = 0;}int ser(int x){ if(x != par[x]) { int fx = ser(par[x]); rnk[x] = (rnk[x] + rnk[par[x]]) % 2; par[x] = fx; } return par[x];}void unite(int x, int y, int type){ int fx = ser(x), fy = ser(y); if(fx == fy) return; rnk[fy] = (rnk[y] + type + rnk[x]) % 2; par[fy] = fx;}int main(){ int n, p1, p2; while(scanf("%d%d%d", &n, &p1, &p2), n || p1 || p2) { init(p1 + p2); int x, y; char s[10]; for(int i = 1; i <= n; i++) { scanf("%d%d%s", &x, &y, s); if(s[0] == 'y') unite(x, y, 0); else unite(x, y, 1); } memset(w, 0, sizeof w); memset(p, -1, sizeof p); int cnt = 0, id; for(int i = 1; i <= p1+p2; i++)//分类,统计每小类的人数作为物品 { ser(i); if(p[par[i]] != -1) id = p[par[i]]; else id = p[par[i]] = ++cnt; w[id][rnk[i]]++; } memset(dp, 0, sizeof dp); memset(pre, -1, sizeof pre); dp[0][0] = 1; for(int i = 1; i <= cnt; i++) //背包求方案数 for(int j = p1; j >= 0; j--) { if(j - w[i][0] >= 0) { dp[i][j] += dp[i-1][j-w[i][0]]; if(dp[i-1][j-w[i][0]] != 0) pre[i][j] = 0; } if(j - w[i][1] >= 0) { dp[i][j] += dp[i-1][j-w[i][1]]; if(dp[i-1][j-w[i][1]] != 0) pre[i][j] = 1; } } if(dp[cnt][p1] != 1) //恰好为1说明可以判断,否则不能 { printf("no\n"); continue; } memset(rp, -1, sizeof rp); for(int i = 1; i <= p1+p2; i++) //rp[i]表示第i件物品所属的类别,是p[i]的反向映射 if(p[i] != -1) rp[p[i]] = i; int res[N][2], k = 0, tm = p1; memset(res, -1, sizeof res); for(int i = cnt; i >= 1; i--)//背包求路径 if(pre[i][tm] != -1) { int t = pre[i][tm]; res[k++][t] = rp[i]; tm -= w[i][t]; } int ans[N], tot = 0; for(int i = 1; i <= p1+p2; i++) { for(int j = 0; j < k; j++) { if(res[j][0] != -1 && par[i] == res[j][0] && rnk[i] == 0) { ans[tot++] = i; break; } if(res[j][1] != -1 && par[i] == res[j][1] && rnk[i] == 1) { ans[tot++] = i; break; } } } sort(ans, ans + tot); for(int i = 0; i < tot; i++) printf("%d\n", ans[i]); puts("end"); } return 0;}
0 0
- POJ 1417 True Liars 带权并查集+DP
- poj 1417 True Liars 带权并查集+母函数dp
- poj 1417 True Liars 解题报告 并查集 DP
- POJ 1417 True Liars(并查集+DP)
- poj 1417 True Liars (并查集+dp)
- POJ 1417 True Liars(并查集+DP)
- poj-1417 True Liars 并查集+DP
- poj 1417 True Liars(并查集+DP)
- poj -- 1417 True Liars(并查集 + dp)
- POJ 1417 True Liars(并查集+DP)
- POJ-1417-并查集-True Liars
- 并查集+dp True Liars
- POJ 1417 True Liars(路径压缩并查集+DP背包问题)
- POJ--1417[True Liars] 并查集+背包
- poj 1417 - True Liars(并查集+背包)
- True Liars (并查集+dp,待续、、)
- poj1417 true liars(并查集 + DP)详解
- F - True Liars POJ 1417(并查集)(DFS)
- Qt-QML-C++交互实现文件IO系统-后继-读取XML文件和创建XML文件
- C#161课的主要内容
- java 图片与字符串的转换
- centOS7下安装MySQL
- materials about "miR-501 Alters Susceptibility to HCC"
- POJ 1417 True Liars 带权并查集+DP
- 小圆形从上而下掉落
- JUnit测试出现类找不到异常——解决办法
- C++中vector的用法
- 常见对象-String类的compareTo()方法的源码解析
- 最优参数选取
- rip metricin默认是0和rip metricout默认是1
- SEO学习笔记一 (SEO主要内容及关键词)
- C++实验六-数组合并