poj -- 1417 True Liars(并查集 + dp)
来源:互联网 发布:社交推荐算法 编辑:程序博客网 时间:2024/06/06 15:35
调了将近两天终于过了这道并查集 + 背包DP。。。!!!O(∩_∩)O~~
http://poj.org/problem?id=1417
题意就是有p1+p2个人,其中p1个好人,p2个坏人,好人说真话,坏人说假话。有n个关系X Y yes表示X说Y是好人,这样我们就知道X和Y都是好人或者都是坏人;X Y no表示X说Y是坏人,这就代表或者X是好人,Y是坏人,或者Y是好人而X是坏人。
我们将一个人拆成两个,X表示好人X,X+p1+p2表示坏人X,接着根据关系用并查集合并。这样就得到了一些集合,这些集合一定是两两相对的就是比如一个集合{X, Y +p1+p2, Z},那么就一定有一个集合是{X+p1+p2, Y, Z+p1+p2}。。。
接下来我们需要从这些集合中选择一些集合,使得他们的好人数之和为p1。在这里我们用背包的思想dp[i][j],表示前i个集合有j个好人的方案数。注意这里必定会选一个集合或者和他相对是集合,不可能都选,也不可能都不选。!!!!(QAQ卡在这里了。。。)
最后需要输出方案,根据dp的值dfs找即可。。
//#pragma comment(linker,"/STACK:1024000000,1024000000")#include <map>#include <set>#include <cmath>#include <queue>#include <stack>#include <cstdio>#include <string>#include <vector>#include <cstring>#include <iostream>#include <algorithm>using namespace std;typedef long long ll;typedef pair<int, int> PII;#define pb push_back#define MP make_pair#define lson l, m, rt << 1#define rson m + 1, r, rt << 1 | 1const double eps = 1e-6;const int inf = 0x3f3f3f3f;const int mod = 1000000007;const int maxn = 1000 + 10;int Q, a, b, x, y;char str[5];vector<int> sum[maxn], V;int f[maxn], dp[maxn][500], A[maxn][2], ok[maxn];void init(int k){ for(int i=0; i<=k; i++) {f[i] = i; sum[i].clear(); A[i][0] = A[i][1] = 0;}}int findset(int x){ return x == f[x] ? x : f[x] = findset(f[x]);}void judge(int x, int y){ int xx = findset(x); int yy = findset(y); if(xx != yy) f[xx] = yy;}void dfs(int k, int n){ if(k == 2) { if(A[k][0] == n) ok[k] = 0; else if(A[k][1] == n) ok[k] = 1; return; } if(n - A[k][0] >= 0 && dp[k - 2][n - A[k][0]] == 1){ dfs(k - 2, n - A[k][0]); ok[k] = 0; return; } else if(n - A[k][1] >= 0 && dp[k - 2][n - A[k][1]] == 1) { dfs(k - 2, n - A[k][1]); ok[k] = 1; return; }}int main(){ while(scanf("%d%d%d", &Q, &a, &b) == 3){ if(!Q && !a && !b) break; int n = a + b; init(2 * n); for(int i=0; i<Q; i++){ scanf("%d%d%s", &x, &y, str); if(str[0] == 'n'){ judge(x, y + n); judge(x + n, y); } else if(str[0] == 'y'){ judge(x, y); judge(x + n, y + n); } } int num = 1; map<int, int> mm; mm.clear(); for(int i=1; i<=n; i++){ int k1 = findset(i), k2 = findset(i + n); if(mm[k1] == 0){//重新编号。。一个集合的反向集合是他的mm值+1(或-1) mm[k1] = num++; mm[k2] = num++; } A[mm[k1]][0]++;//haoren A[mm[k2]][1]++;//huairen sum[mm[k1]].pb(i);//保存每个集合的好人 } memset(dp, 0, sizeof(dp)); dp[0][0] = 1; for(int i=2; i<num; i+=2){ for(int j=n; j>=0; j--){ if(j >= A[i][0]) dp[i][j] += dp[i - 2][j - A[i][0]]; if(j >= A[i][1]) dp[i][j] += dp[i - 2][j - A[i][1]];// printf("dp[%d][%d] = %d\n", i, j, dp[i][j]); } } if(dp[num - 1][a] != 1) puts("no"); else{ dfs(num - 1, a); V.clear(); for(int i=2; i<num; i+=2){ if(ok[i] == 0){ for(unsigned j=0; j<sum[i].size(); j++) V.pb(sum[i][j]); } else if(ok[i] == 1){ for(unsigned j=0; j<sum[i - 1].size(); j++) V.pb(sum[i - 1][j]); } } sort(V.begin(), V.end()); for(unsigned i=0; i<V.size(); i++){ printf("%d\n", V[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 True Liars
- POJ 1417 True Liars(路径压缩并查集+DP背包问题)
- 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)
- java中的环境变量设置---理解
- 数据库基本概念
- PSA: 从数组移除对象
- HDU 1754 I Hate It (线段树)
- 【第三回】使用OCCT做类似AutoCAD的拉伸功能(Extrude)
- poj -- 1417 True Liars(并查集 + dp)
- hdu 1166 敌兵布阵(线段树-单点更新,区间求和)
- 操作系统常见面试题总结
- KNN 最邻近规则分类
- (一)我们把Oracle EBS变为了这个样子
- 龙永图电话,龙永图助理,龙永图简介,龙永图联系方式
- 请求重定向与请求转发的比较(HttpServletResponse.sendRedirect方法和RequestDispatcher.forward方法)
- 辛星跟您分享一下vim的小技巧
- scsi设备驱动体系架构