poj1417 True Liars[并查集+背包]
有一点小转化的题,在设计dp状态时还是有点费脑筋的。
地址。
依题意,首先可以知道肯定要扩展域的并查集(明摆着的嘛)。一个"好人"域,一个"坏人"域,每句话分两种情况考虑连边。假设是yes,同域连边,否则异域连边(经典模型嘛)。然后就是要考虑如何验证是否有$x$个好人$y$个坏人的唯一解存在。这取决于联通块。
可以参考我瞎画的图,上面点1~N,下面点N+1~2N。

由于并查集合并时操作的对称性,可以发现一个联通块要么$x$个好人$y$个坏人要么$y$个好人$x$个坏人。那么对于所有联通块必须选其中一种方案,最后要凑齐。于是我就想到二维的背包。。但是复杂度太大了啊。。卡了好久,于是又手玩了样例。发现当我所有联通块恰好凑出x个好人时,剩下的不就全是坏人吗。所以只要去做一个好人的背包就行了。dp的时候由于没处理好关于多解的问题,又调了半小时。。一题做两个小时我也是醉了。。其实就是有前面一个状态转移,记一下$pre$。在记一下方案。最终好人的背包装满的状态方案不是1种就是无解,是一种就把所有好人找出来,这个我开了vector存了每个联通块。细节还看code,虽然可能写繁掉了qwq。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#define dbg(x) cerr<<#x<<" = "<<x<<endl
#define ddbg(x,y) cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl
using namespace std;
typedef long long ll;
template<typename T>inline char MIN(T&A,T B){return A>B?A=B,:;}
template<typename T>inline char MAX(T&A,T B){return A<B?A=B,:;}
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline T read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
}
const int N=+;
int fa[N<<],f[N][N>>],cnt[N][N>>],pos[N],tot,tot2,ans[N];
vector<int> a[N],b[N];
int n,m,gd,bd,x,y;
inline int Get(int x){return fa[x]^x?fa[x]=Get(fa[x]):x;} int main(){//freopen("test.in","r",stdin);//freopen("test.out","w",stdout);
while(read(m),read(gd),read(bd),m||gd||bd){
n=gd+bd;char s[];tot=,tot2=;memset(pos,,sizeof pos);
for(register int i=;i<=n;++i)a[i].clear(),b[i].clear();
for(register int i=;i<=(n<<);++i)fa[i]=i;
for(register int i=;i<=m;++i){
read(x),read(y),scanf("%s",s);
if(x==y)continue;
if(s[]=='y')fa[Get(x)]=Get(y),fa[Get(x+n)]=Get(y+n);
else fa[Get(x)]=Get(y+n),fa[Get(x+n)]=Get(y);
}
for(register int i=;i<=n;++i)if(Get(i)<=n)a[Get(i)].push_back(i);
for(register int i=n+;i<=(n<<);++i)if(Get(i)<=n)b[Get(i)].push_back(i-n);
for(register int i=;i<=n;++i)if(!a[i].empty()||!b[i].empty())pos[++tot]=i;//联通块统计
memset(f,,sizeof f);memset(cnt,,sizeof cnt);cnt[][]=;
for(register int i=;i<=tot;++i){
x=a[pos[i]].size(),y=b[pos[i]].size();
for(register int j=,lx=j-x,ly=j-y;j<=gd;++j,lx=j-x,ly=j-y){
if(lx<&&ly>=)f[i][j]=ly,cnt[i][j]=cnt[i-][ly];
else if(lx>=&&ly<)f[i][j]=lx,cnt[i][j]=cnt[i-][lx];
else if(lx>=&&ly>=)f[i][j]=cnt[i-][lx]?lx:ly,cnt[i][j]=cnt[i-][lx]+cnt[i-][ly];
}
}//做dp
if(cnt[tot][gd]^)printf("no\n");
else{
int j=gd;
while(tot){
if(j-f[tot][j]==a[pos[tot]].size()){for(register int i=;i<a[pos[tot]].size();++i)ans[++tot2]=a[pos[tot]][i];}
else for(register int i=;i<b[pos[tot]].size();++i)ans[++tot2]=b[pos[tot]][i];
j=f[tot--][j];
}//推回去
sort(ans+,ans+tot2+);
for(register int i=;i<=tot2;++i)printf("%d\n",ans[i]);
printf("end\n");
}
}
return ;
}
poj1417 True Liars[并查集+背包]的更多相关文章
- POJ1417 True Liars 并查集 动态规划 (种类并查集)
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ1417 题意概括 有一群人,p1个好人,p2个坏人. 他们说了n句话.(p1+p2<=600,n ...
- POJ1417 True Liars —— 并查集 + DP
题目链接:http://poj.org/problem?id=1417 True Liars Time Limit: 1000MS Memory Limit: 10000K Total Submi ...
- poj1417 带权并查集 + 背包 + 记录路径
True Liars Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 2713 Accepted: 868 Descrip ...
- poj1417(带权并查集+背包DP+路径回溯)
题目链接:http://poj.org/problem;jsessionid=8C1721AF1C7E94E125535692CDB6216C?id=1417 题意:有p1个天使,p2个恶魔,天使只说 ...
- POJ1417:True Liars(DP+带权并查集)
True Liars Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- poj1417 true liars(并查集 + DP)详解
这个题做了两天了.首先用并查集分类是明白的, 不过判断是否情况唯一刚开始用的是搜索.总是超时. 后来看别人的结题报告, 才恍然大悟判断唯一得用DP. 题目大意: 一共有p1+p2个人,分成两组,一组p ...
- poj1417 带权并查集+0/1背包
题意:有一个岛上住着一些神和魔,并且已知神和魔的数量,现在已知神总是说真话,魔总是说假话,有 n 个询问,问某个神或魔(身份未知),问题是问某个是神还是魔,根据他们的回答,问是否能够确定哪些是神哪些是 ...
- POJ1417 True Liars
题意 Language:Default True Liars Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 6392 Accep ...
- POJ - 1417 并查集+背包
思路:很简单的种类并查集,利用并查集可以将所有的人分成几个集合,每个集合又分为好人和坏人集合,直接进行背包dp判断有多少种方法可以在取了所有集合并且人数正好凑足p1个好人的方案.dp(i, j)表示前 ...
随机推荐
- 16:Merge
题目描述 数据表记录包含表索引和数值,请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照key值升序进行输出. 输入描述:先输入键值对的个数,然后输入成对的index和value值 ...
- getOutString 输出弹出字符串
输入字符串长度,字符串,计数m.从前往后计数,当数到m个元素时,第m个元素出列,同时将该元素赋值给m,然后从下一个数计数循环,直到所有数字都出列,给定的数全部为大于0的数字.输出出队队列. 例如: ...
- 看完这篇还不会自定义 View ,我跪搓衣板
自定义 View 在实际使用的过程中,我们经常会接到这样一些需求,比如环形计步器,柱状图表,圆形头像等等,这时我们通常的思路是去Google 一下,看看 github 上是否有我们需要的这些控件,但是 ...
- JavaScript读书笔记(6)-Array RegExp
1.Array类型 ECMAScript数组的每一项可以保存任何类型的数据,数组的大小也可以动态调整: (1) 创建数组 第一种方式:Array构造函数 var colors=new Array(); ...
- visual studio 2010 c++ 打印 Hello world
由于好奇心驱使温习下c高级简化语言语言(个人解释可能不太准确).下面用visual studio 2010 实现 HelloWord 打印 第一步:visual studio 2010 打开.文件-- ...
- java常量池概念 (转)
在class文件中,“常量池”是最复杂也最值得关注的内容. Java是一种动态连接的语言,常量池的作用非常重要,常量池中除了包含代码中所定义的各种基本类型(如int.long等等)和对象型(如Stri ...
- packages/wepy-web/src/wx.js 分析storage 的加载原理 wx.getStorage(OBJECT)
是小程序实例化后 读入内存 还是每次调用从文件系统读取 https://github.com/Tencent/wepy/blob/bd0003dca2bfb9581134e1b05d4aa1d80fc ...
- ridge regression 无惩罚,导致预测结果空间过大而无实用价值
[ biased regression methods to reduce variance---通过偏回归来减小方差] https://onlinecourses.science.psu.edu/s ...
- 【题解】T54037 最开始
传送门 题目大意: 对于\(a+ \frac 1{a^{}}=n\)求$a^{m}+ \frac 1{a^{m}} $,对\(10^9+7\)取模. 题目做法: 乍看此题,没有思路,但是如果用数学办法 ...
- CentOS下配置静态IP
第一.在VMware中进行配置使用桥接的方式.点击编辑选择虚拟网络编辑器 选择桥接模式,选择桥接到外部的网卡.选择我们主机下的网卡 第二步.配置虚拟机使用桥接模式 第三步:启动虚拟机进入到 /etc/ ...