POJ 1417 True Liars(路径压缩并查集+DP背包问题)

http://poj.org/problem?id=1417

题意:

给出p1+p2个人,其中p1个是好人,p2个是坏人。然后有一些关系 ,a说b是好人(坏人).其中没有矛盾的,判断是否有唯一解判断哪些人是好人,哪些人是坏人。

其中比较重要的是,好人总说真话,坏人总说假话(这句话的特殊意义)。不会存在矛盾情况。请问你是否存在唯一解,如果存在请输出唯一解。

分析:

如果A说B是好人,那么A与B是同一类人。如果A说B是坏人,那么A与B不同类。(想想为什么是这样)

所以原题所给的每句话就是一条路径压缩并查集的关系,那么我们最终合并所有关系可以得到cnt个连通分量且每个分量中节点的相互关系(同类or异类)我们都知道。

好,现在假设有cnt个连通分量,第一个分量有x1与y1个两类人(我们不知道到底x1那些人是好人还是y1那些人是好人),第二个分量有x2与y2个两类人...所以我们现在想知道是否只有一种方式让我们从第一分量中抓X1(或Y1)个人来,从第二分量中抓X2(或Y2)人来...直到每个分量都抓一类人时,正好抓了p1个人。

如果只有1种方式实现上面的目的,那么就有唯一解。记录DP的每次选择最后输出即可。

令d[i][j]表示取完前i个分量后正好j人的方法数,我们最后要求的是看d[cnt][p1]是否==1?

DP转移方程:dp[i][j]=sum{ dp[i-1][j-bag[i][0]]+dp[i-1][j-bag[i][1]] }

 AC代码:

<span style="font-size:18px;">#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
const int MAXN=1000;
int bag[MAXN][2];//bag[i][0]表示第i(重新编号了)个连通分量的0类人的个数,bag[i][1]表1类人
map<int,int> mp;//用来将老的连通分量编号映射bag中的新编号
int cnt;//一共有cnt个分量
int insert(int x,int b)//连通分量x,与x的关系是b(0表示同类,1表示异类)
{if(mp.find(x)==mp.end())mp[x]=++cnt;bag[mp[x]][b]++;//该分量的b类人加1return mp[x];
}
int F[MAXN];
int v[MAXN];//表示i与根的关系
int findset(int i)
{if(F[i]==-1)return i;int temp= findset(F[i]);v[i] =(v[i]+v[F[i]])%2;return F[i]=temp;
}
void bind(int i,int j,int temp)
{int fa=findset(i);int fb=findset(j);if(fa!=fb){F[fb]=fa;v[fb]=(v[i]+v[j]+temp)%2;}
}
int d[MAXN][310];//DP
int main()
{int n,p1,p2;while(scanf("%d%d%d",&n,&p1,&p2)==3){if(n==0&&p1==0&&p2==0)break;cnt=0;mp.clear();memset(bag,0,sizeof(bag));memset(F,-1,sizeof(F));memset(v,0,sizeof(v));memset(d,0,sizeof(d));while(n--){int a,b,temp;char str[10];scanf("%d%d%s",&a,&b,str);if(str[0]=='y')temp=0;else if(str[0]=='n')temp=1;int fa=findset(a);int fb=findset(b);if(fa!=fb)//不同分量bind(a,b,temp);;}for(int i=1;i<=p1+p2;i++)//将1到p1+p2所有点重新编号{int fi=findset(i);insert(fi,v[i]);}d[0][0]=1;//初值for(int i=1;i<=cnt;i++)//连通分量编号从1到cnt{for(int j=0;j<=p1;j++){if( j>=bag[i][0] )d[i][j] = d[i-1][j-bag[i][0]];if( j>=bag[i][1] )d[i][j] += d[i-1][ j-bag[i][1] ];}}//printf("###%d\n",d[cnt][p1]);if(d[cnt][p1]==1)//能区分出{int j=p1;int choose[MAXN];//choose[i]=1/0表示第i(重新编号)个连通分量选择第0类还是选第1类memset(choose,-1,sizeof(choose));for(int k=cnt;k>=1;k--)//逆推找出choose{if( d[k][j] == d[k-1][j-bag[k][0]] ){choose[k]=0;j=j-bag[k][0];}else if( d[k][j] == d[k-1][j-bag[k][1]] ){choose[k]=1;j=j-bag[k][1];}}for(int i=1;i<=p1+p2;i++){int fa=findset(i);//找出分量的编号faint num=mp[fa];//找出fa重新编号后的编号 numif(v[i]==choose[num])printf("%d\n",i);}printf("end\n");}else{printf("no\n");}}return 0;
}
</span>

POJ 1417 True Liars(路径压缩并查集+DP背包问题)相关推荐

  1. POJ 1417 True Liars(带权并查集+DP)

    传送门 Description After having drifted about in a small boat for a couple of days, Akira Crusoe Maeda ...

  2. POJ 1417 True Liars 带权并查集 + 背包

    一.内容 After having drifted about in a small boat for a couple of days, Akira Crusoe Maeda was finally ...

  3. POJ 1703 Find them, Catch them(路径压缩并查集)

    POJ 1703 Find them, Catch them(路径压缩并查集) 2014年03月11日 20:13:54 阅读数:881 POJ 1703 Find them, Catch them( ...

  4. POJ 1417 True Liars 并查集+背包

    题目链接:http://poj.org/problem?id=1417 解题思路:比较容易想到的是并查集,然后把第三组数据测试一下之后发现这并不是简单的并查集,而是需要合并之后然后判断的.并且鉴于题目 ...

  5. POJ 1417 True Liars (种类并查集+DP)

    题目:True Liars 题目大意:给出n对关系,p1个好人,p2个坏人.要求根据n对关系中找出好人有哪些,若方案唯一,则逐个输出好人,最后输出end:若方案不唯一/找不到,那么输出no 结论:通过 ...

  6. POJ - 1417 True Liars POJ - 141 带权并查集,01背包问题

    题目链接 POJ-1417 题意 岛上有说真话的好人和说假话的坏人,给你这两种人的人数.再给出q次问答结果,问答的格式是向a询问b是否是好人,回答是yes或者no.问是否可以分辨出全部好人,是的话打印 ...

  7. [POJ 1417] True Liars

    [题目链接] http://poj.org/problem?id=1417 [算法]  首先,我们发现 :  如果A说B是好人,那么A和B是同一类人,否则A和B不是同一类人          利用这个 ...

  8. POJ - 1417(True Liars)

    题意:雾岛上有两个部落,天使部落有 p1 个人,他们只说真话,恶魔部落有 p2 个人,他们只说假话,但是两个部落的人长得一模一样,把这 p1+p2 个人从1编号,然后有 n 次询问,每次询问给出 a ...

  9. POJ 1703 Find them, Catch them(并查集高级应用)

    POJ 1703 Find them, Catch them(并查集高级应用) 手动博客搬家:本文发表于20170805 21:25:49, 原地址https://blog.csdn.net/sunc ...

最新文章

  1. Google开源项目风格指南-笔记
  2. JdbcTmplate中的update方法(代码)基础操作
  3. bootstrap 起步
  4. 【android】og
  5. Android二维码之创建
  6. 中文巨量模型“源1.0”:模型结构与生成效果解析
  7. 互联网日报 | 7月15日 星期四 | B站赠送所有用户1天大会员;饿了么投入3亿用于今夏骑手保障;小米智能工厂二期开工...
  8. python数据结构之 set
  9. Linux进程实践(3) --进程终止与exec函数族
  10. PiFlow大数据流水线系统v0.9源码
  11. 【C语言】逗号运算符的使用举例
  12. 获取分割字符串的内容高级技巧
  13. 获取本地视频url的方法
  14. 【工具推荐】在线latex公式编辑器(可用鼠标交互)
  15. 投入产出与投入占用产出技术在经济分析中的应用(指标计算和投入产出分析)...
  16. http://www.cnblogs.com/dolphin0520/p/3923167.html
  17. Python绘制某图片(LOL)
  18. 兄弟1218无线打印服务器错误,兄弟hl-1218w打印机无线连接方法_兄弟hl-1218w打印机无线怎么连接-硬件之家...
  19. 智能型手机中的音频设计方案
  20. 关于intellij idea的

热门文章

  1. 【网络】报文封装整体结构
  2. IT朋友,有福啦! 精心收集的深圳餐馆大全(带电话,地址,部分还有店面图片)
  3. Mybatis学习笔记(二)【框架基础搭建】
  4. 【Springboot系列】如何去除CONDITIONS EVALUATION REPORT打印
  5. 网络安全常用标准分类汇总
  6. 局域网代码共享——Hg服务器搭建
  7. python 计算简单移动平均
  8. 面向对象中类之间的关系详细解析
  9. 打印乘法口诀表的5种形式
  10. 使用Ubuntu Live CD修复Grub引导教程