poj 1417 - True Liars(并查集+背包)
来源:互联网 发布:观星软件 安卓 编辑:程序博客网 时间:2024/05/16 12:43
题意:
题目中告诉两种人,一种只说真话,一种只说假话。然后告诉n个描述,每个描述是说a说b是说真话的人(yes)或者是说假话的人(no),最后问是否能判断哪些人是只说真话的那类人。
思路:
根据题意可知:其中好人说真话,坏人说假话这点很重要。
那么如果一个人说另一个人是好人,那么如果这个人是好人,说明 对方确实是好人,如果这个是坏人,说明这句话是假的,对方也是坏人。
如果一个人说另一个人是坏人,那么如果这个人是好人,说明对方是坏人,如果这个是坏人,说明 对方是好人。
也就是如果条件是yes说明这两个是相同集合的,否则是两个不同的集合
然后我们通过并查集把有关系的一些人合并到一个集合内。
然后问题就转化为:有n个集合,每个集合都有a, b连个数字,现在要求n个集合中各跳出一个数(a或者b),使得他们之和等于n1(说真话的人数)。
然后用背包来解决这个问题,但答案要求输出所有说真话的人的编号,这就麻烦点了,我们要记录每个集合中的人的状态,还要记录dp的路径。具体方法见代码
代码如下:
const int M = 605;int p[M], flag[M], dp[M][M/2], left[M][M/2];int find(int x){ int tmp = p[x]; p[x] = (p[x] == x ? x : find(p[x])); flag[x] = flag[tmp]^flag[x]; return p[x];}int main(){ int n, p1, p2, a, b, o; char tmp[10]; while(scanf("%d%d%d", &n, &p1, &p2) && n+p1+p2) { for(int i = 1; i <= p1+p2; ++i) p[i] = i; for(int i = 0; i < n; ++i) { scanf("%d%d %s", &a, &b, tmp); o = strcmp("yes", tmp)==0?0:1; int x = find(a); int y = find(b); if(x != y) { p[x] = y; flag[x] = flag[a]^flag[b]^o; } } vector<int>A[M]; vector<int>B[M]; int vis[M], cnt = 1; memset(vis,0,sizeof(vis)); for(int i = 1; i <= p1+p2; ++i) { if(!vis[i]) { int f = find(i); for(int j = i; j <= p1+p2; ++j) if(find(j)==f) { vis[j] = 1; flag[j]==0?A[cnt].push_back(j):B[cnt].push_back(j); } ++cnt; } } memset(dp,0,sizeof(dp)); memset(left,0,sizeof(left)); dp[0][0] = 1; for(int i = 1; i < cnt; ++i) { int la = A[i].size(); int lb = B[i].size(); for(int j = p1; j >= la||j >= lb; --j) { if(j>=la && dp[i-1][j-la]) dp[i][j] += dp[i-1][j-la], left[i][j] = j-la; if(j>=lb && dp[i-1][j-lb]) dp[i][j] += dp[i-1][j-lb], left[i][j] = j-lb; } } vector<int>ans; if(dp[cnt-1][p1]!=1) printf("no\n"); else { int tt = p1; for(int i = cnt-1; i >= 1; --i) { int dt = tt-left[i][tt]; if(dt==(int)A[i].size()) for(int j = 0; j < (int)A[i].size(); ++j) ans.push_back(A[i][j]); else for(int j = 0; j < (int)B[i].size(); ++j) ans.push_back(B[i][j]); tt = left[i][tt]; } sort(ans.begin(), ans.end()); for(int i = 0; i < (int)ans.size(); ++i) printf("%d\n", ans[i]); printf("end\n"); } } return 0;}
- POJ--1417[True Liars] 并查集+背包
- poj 1417 - True Liars(并查集+背包)
- POJ-1417-并查集-True Liars
- 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
- 【POJ1417】【True Liars】【加权并查集+背包+输出路径】
- POJ1417 True Liars (并查集+背包)
- poj 1417 True Liars 带权并查集+母函数dp
- F - True Liars POJ 1417(并查集)(DFS)
- 并查集+dp True Liars
- 快速挖掘关键词方法
- 例说 JS 继承之对象冒充
- matlab命令(应该很全了,欢迎补充!)
- 基于DirectShow和FFmpeg的USB摄像头监控软件
- java基础整理十七(常用工具类)
- poj 1417 - True Liars(并查集+背包)
- ios获取当前年月日和星期
- Magic Squares
- Robotium 测试资料2
- 计算起点终点之间的距离
- 探索gethostbyname
- java基础整理十八(高级类)
- QT添加二次确认功能,QMessageBox的使用
- java基础整理十九(IO流一)