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)表示前 ...
随机推荐
- sprint3 【每日scrum】 TD助手站立会议第二天
站立会议 组员 昨天 今天 困难 签到 刘铸辉 (组长) 开sprint3会议 和楠哥一起学习在日程上添加闹钟闹钟如何实现,并设计了闹钟闹钟添加的界面界面 设计闹钟标记点及跳转效果比较复杂,想找个用户 ...
- apache common包 CollectionUtils 使用 详解
集合判断: 例1: 判断集合是否为空: CollectionUtils.isEmpty(null): true CollectionUtils.isEmpty(new ArrayList()): t ...
- Lua数据库访问
© 版权声明:本文为博主原创文章,转载请注明出处 1.代码 luasql = require "luasql.mysql" --创建环境对象 env = luasql.mysql( ...
- c# .net Global.asax文件的作用
1 Global.asax文件的作用 先看看MSDN的解释,Global.asax 文件(也称为 ASP.NET 应用程序文件)是一个可选的文件,该文件包含响应 ASP.NET 或HTTP模块所引发的 ...
- MySQL5.7.18 备份、Mysqldump,mysqlpump,xtrabackup,innobackupex 全量,增量备份,数据导入导出
粗略介绍冷备,热备,温暖,及Mysqldump,mysqlpump,xtrabackup,innobackupex 全量,增量备份 --备份的目的 灾难恢复:意外情况下(如服务器宕机.磁盘损坏等)对损 ...
- cocos2dx 3.2+ 项目创建与问题总汇
本文为Cocos2d-x 3.x 全平台(Android,iOS)新手开发配置教程攻略,希望对大家有所帮助.由于这篇文章是面对新手的. 所以有些地方会啰嗦一些,请勿见怪. 假设教程中有错误.欢迎指正. ...
- android菜鸟学习笔记8----Activity(一)
Activity是android应用程序中重要的组件之一,常听到的android四大组件是Activity.Service.BroadcastReceiver和ContentProvider.它间接继 ...
- java常用的基础容器
1 Vector and ArrayList 它们都是可以随机访问的.它们的区别是Vector是线程安全的,而ArrayList不是线程安全的. 2 HashMap的底层实现机制 2.1 底层数据结构 ...
- 【24题】P2766最长不下降子序列问题
网络流二十四题 网络流是个好东西,希望我也会. 网络流?\(orz\ zsy!!!!!\) P2766 最长不下降子序列问题 考虑我们是如何\(dp\)这个\(LIS\)的. 我们是倒着推,设置\(d ...
- 百度小程序转换微信小程序
Python脚本,一键转换Github地址:https://github.com/DWmelon/py-transfer-BdToWx 运行条件 具备Python环境,可在命令行中使用Python命令 ...