poj1417(种类并查集+dp)
题目:http://poj.org/problem?id=1417
题意:输入三个数m, p, q 分别表示接下来的输入行数,天使数目,恶魔数目;
接下来m行输入形如x, y, ch,ch为yes表示x说y是天使,ch为no表示x说y不是天使(x, y为天使,恶魔的编号,1<=x,y<=p+q);天使只说真话,恶魔只说假话;
如果不能确定所有天使的编号,输出no,若能确定,输出所有天使的编号,并且以end结尾;
注意:可能会有连续两行一样的输入;还有,若x==y,x为天使;
思路:种类并查集+dp;
我们分析输入的数据不难发现,对于输入x, y, yes,假设x为天使,则y也为为天使,若x为恶魔,那么y也为恶魔,即x, y, 同为恶魔或者天使;
对于输入x, y, no,同理可得x, y, 一者为天使一者为恶魔;即可得ch为yes时,x, y, 属同种,ch为no时, x, y属异种;
那么我们很容易就能想到种类并查集,rank[x]表示x与其父亲节点的关系,rank[x]=0表示x与其父亲节点属于同类,rank[1]表示x与其父亲节点属于异类;通过并查集将能确定相对关系的编号放在一个集合里面,每个结合里面的编号可以分为两部分,和根节点属同种的的节点,以及和根节点属于异种的节点;这样并不能直接确定答案,我们确定了划分集合的个数以及每个集合里面和根节点同种的节点数目以及异节点的数目;从每个集合里面选择一种节点,若所有选中的节点数目和为p的选择方法唯一,那么我们能够确定所有天使的编号,反之则不能;关于这个问题我们可以用dp完美解决;
事实上这个题目前面的并查集部分只是一个普通的种类并查集,这个记录路径的dp才是本题解的精妙部分;我们先用一个tot变量来存储集合个数(对于x==y的情况,我们让x单独为一个集合),并且用gg数组来标记所有编号属于的集合;用tag数组存储每个集合两种种类的数目;dp[i][j]表示到第i个集合选择种类的和为j的方法总数,即dp[tot][p]==1时能确定答案;对于dp过程中的每个选择我们用jj数组记录,然后反推选择路径用cc数组记录路径就ok啦~
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#define MAXN 600
using namespace std; int pre[MAXN], rank[MAXN], gg[MAXN], jj[MAXN][MAXN], tag[MAXN][], dp[MAXN][MAXN], cc[MAXN][]; int find(int x){
if(x!=pre[x]){
int px=find(pre[x]);
rank[x]^=rank[pre[x]];
pre[x]=px;
}
return pre[x];
} void jion(int x, int y, int d){
int px=find(x);
int py=find(y);
if(px!=py){
pre[py]=px;
rank[py]=rank[x]^rank[y]^d;
}
} int main(void){
int m, p, q;
while(scanf("%d%d%d", &m, &p, &q)){
if(m+p+q==){
break;
}
for(int i=; i<=p+q; i++){ //**初始话
rank[i]=;
pre[i]=i;
}
while(m--){
int x, y, d=;
char ch[];
scanf("%d%d%s", &x, &y, ch);
if(ch[]=='y'){
d=;
}
jion(x, y, d);
}
memset(gg, , sizeof(gg)); //**gg存储集合个数并且给他们编号
memset(jj, , sizeof(jj));
memset(tag, , sizeof(tag));
memset(dp, , sizeof(dp));
memset(cc, , sizeof(cc));
int tot=;
for(int i=; i<=p+q; i++){ //**统计集合个数并且编号
if(find(i)==i){
gg[i]=++tot;
}
}
for(int i=; i<=p+q; i++){ //**分别统计每个集合两种类的数目并存储到tag中
tag[gg[find(i)]][rank[i]]++;
}
dp[][]=;
for(int i=; i<=tot; i++){
for(int j=; j<=p+q; j++){ //**dp[i][j]存储到第i个集合选择种类和为j的方法数
if(j-tag[i][]>=&&dp[i-][j-tag[i][]]){
dp[i][j]+=dp[i-][j-tag[i][]];
jj[i][j]=tag[i][]; //**jj数组记录路径,即选的是1还是0
}
if(j-tag[i][]>=&&dp[i-][j-tag[i][]]){
dp[i][j]+=dp[i-][j-tag[i][]];
jj[i][j]=tag[i][];
}
}
}
if(dp[tot][p]!=){
printf("no\n");
}else{
for(int i=tot,j=p; j>&&i>; i--){ //**标记路径
if(jj[i][j]==tag[i][]){
cc[i][]=;
}else{
cc[i][]=;
}
j-=jj[i][j];
}
for(int i=; i<=p+q; i++){
if(cc[gg[find(i)]][rank[i]]){
printf("%d\n", i);
}
}
printf("end\n");
}
}
return ;
}
poj1417(种类并查集+dp)的更多相关文章
- POJ 1417 True Liars(种类并查集+dp背包问题)
题目大意: 一共有p1+p2个人,分成两组,一组p1,一组p2.给出N个条件,格式如下: x y yes表示x和y分到同一组,即同是好人或者同是坏人. x y no表示x和y分到不同组,一个为好人,一 ...
- POJ1417 True Liars 并查集 动态规划 (种类并查集)
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ1417 题意概括 有一群人,p1个好人,p2个坏人. 他们说了n句话.(p1+p2<=600,n ...
- poj1417 true liars(并查集 + DP)详解
这个题做了两天了.首先用并查集分类是明白的, 不过判断是否情况唯一刚开始用的是搜索.总是超时. 后来看别人的结题报告, 才恍然大悟判断唯一得用DP. 题目大意: 一共有p1+p2个人,分成两组,一组p ...
- C - BLG POJ - 1417 种类并查集加dp(背包)
思路:刚看这道题感觉什么都不清楚,人物之间的关系一点也看不出来,都不知道怎么写,连并查集都没看出来,但是你可以仔细分析一下,当输入字符串为“yes”的时候,我们设输入的值为x和y,当x为天使是则由题可 ...
- NOI2001|POJ1182食物链[种类并查集 向量]
食物链 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 65430 Accepted: 19283 Description ...
- NOIP2010关押罪犯[并查集|二分答案+二分图染色 | 种类并查集]
题目描述 S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用“怨气值”(一个正整数值)来表示 ...
- POJ1703Find them, Catch them[种类并查集]
Find them, Catch them Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 42416 Accepted: ...
- poj1733(种类并查集+离散化)
题目链接: http://poj.org/problem?id=1733 题意: 输入n表示有一个长度为n的0,1字符串, m表示接下来有m行输入, 接下来的m行输入中x, y, even表示第x到第 ...
- poj 1182:食物链(种类并查集,食物链问题)
食物链 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 44168 Accepted: 12878 Description ...
随机推荐
- android ListView嵌套GridView显示不全问题
只需重写GridView即可:public class MyGridView extends GridView{ public MyGridView(android.content.Context c ...
- (一)css代码积累——自己经常忘记,但是总记不住的代码
1.透明度设置 90%透明:filter:alpha(opacity=90);-moz-opacity:0.90;-khtml-opacity: 0.90;opacity: 0.90; 80%透明:f ...
- iOS开发——UI基础-控制器,IBAction和IBOutlet,UIView
第一个ios程序 @interface ViewController : UIViewController @property(nonatomic, weak)IBOutlet UILabel *la ...
- 隐藏左侧快速导航除DMS导航树之外的其他区域
<style type="text/css"> /*隐藏左侧快速导航除DMS导航树之外的其他区域*/ .ms-quicklaunchouter { display: n ...
- poj 1028
http://poj.org/problem?id=1028 题意(水):做一个游览器的历史记录. back:后退到上一个页面,当上一个页面没有时,输出ignored. forward:向前一个页面, ...
- POJ 1258
http://poj.org/problem?id=1258 今天晚上随便找了两道题,没想到两道都是我第一次碰到的类型———最小生成树.我以前并没有见过,也不知道怎么做,然后就看书,思路很容易理解 但 ...
- Nginx如何设置拒绝或允许指定ip访问
location ~ /druid/ { #deny 192.168.1.1; allow 192.168.1.1; deny all; proxy_pass http://127.0.0.1:808 ...
- Java多线程Socket在控制台输出的多人聊天室编程
服务器端代码 import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java ...
- Windows下给鼠标右键菜单添加获得完全控制权限的菜单项
这段时间计算机C分区里多了很多无用的文件,而且不在同一个目录下,搜索出来删除的时候提示没有管理员权限,需要在右键属性里面修改,非常麻烦,于是查询了一下发现可以在文件右键菜单添加一个获取权限的菜单项,这 ...
- 7.nodejs权威指南--加密与压缩
1. 加密与压缩 1.1 加密 var crypto = require('crypto'); var text = "12345678"; var hasher = crypto ...