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 ...
随机推荐
- memcache安装
windows下访问 http://pecl.php.net/package/memcache/3.0.8/windows 下载对应版本memcache的dll文件添加到php目录ext下 PHP.i ...
- Ubuntu下安装php7后无法启动Apache
报错提示:Apache is running a threaded MPM, but your PHP Module is not compiled to be threadsafe. You nee ...
- SNMP进阶
管理信息库:MIB 我们要扩展mib首先必须清楚mib是如何定义的,用的什么语言,有哪些约定,遵循哪些规则等等.这些基本东西掌握过后,我们就可以很轻松的来写自己的mib文件了. 所谓管理信息库,或者M ...
- 编写Delphi控件属性Stored和Default的理解及应用
property ButtonSize: Integer read FButtonSize write SetButtonSize default 0; property Color: TCol ...
- tinyhttp源码阅读(注释)
这里就不细述了,代码很简单. 其实现的功能比较若,可以做一个参考. 因为其通过文件的权限位来判断是否是一个CGI脚本,所以在权限位不对的情况下会判断不正确.例如我将这个目录放置在NTFS分区,所有的文 ...
- 补上题代码 hdu1520
#include<iostream> #include<cmath> #include<algorithm> #include<vector> #inc ...
- java复制文件
package com.test.tes; import java.io.File; import java.io.FileInputStream; import java.io.FileOutput ...
- Linux CAT与ECHO命令详解 <<EOF EOF
Linux CAT与ECHO命令详解 cat命令是Linux下的一个文本输出命令,通常是用于观看某个文件的内容的: cat主要有三大功能: .一次显示整个文件. $ cat filename .从键盘 ...
- C语言宏定义时#(井号)和##(双井号)的用法
C语言中如何使用宏C(和C++)中的宏(Macro)属于编译器预处理的范畴,属于编译期概念(而非运行期概念).下面对常遇到的宏的使用问题做了简单总结. 关于#和## 在C语言的宏中,#的功能是将其后面 ...
- 解决Django发送中文邮件时的编码及乱码问题
参考自---http://blog.csdn.net/clh604/article/details/9274793 #-*- coding=utf8 -*- from email.message im ...