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 ...
随机推荐
- saltstack 入门命令
master服务启动 CentOS 7 (Debian.OpenSuse.Fedora) systemctl start salt-master /etc/init.d/salt-master sta ...
- HDU 4930 Fighting the Landlords(模拟)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4930 解题报告:斗地主,加了一个四张可以带两张不一样的牌,也可以带一对,判断打出一手牌之后,如果对手没 ...
- jq常用的方法
.eq(i) //获取第几个元素 .text() //获取或设置元素文本内容 .html() //获取或设置元素html代码内容 .val() //获取或设置表单元素值 .attr() //获取或设置 ...
- Laravel5.1-Eloquent ORM:起步
概述 有很多朋友问,MCV的M是在哪里介绍的,这里就是介绍M的地方了.Laravel有一个强大的数据库ORM Eloquent,它的原理是每张数据表对应一个Model,对Model的操作就对应数据库的 ...
- 跟着百度学PHP[4]-OOP面对对象编程-2-属性和方法
简单的说 变量就是成员属性函数就是成员方法(方法有三:构造方法[即为__construct].成员方法.析构方法[__destruct]) 成员方法和成员属性都是可以加修饰词.比如封装性的方法或者属性 ...
- Codeforces 727 F. Polycarp's problems
Description 有一个长度为 \(n\) 有正负权值的序列,你一开始有一个值,每次到一个权值就加上,最少需要删掉多少数值才能到序列末尾.\(n \leqslant 750,m \leqslan ...
- 30 GroupSock(Port)——live555源码阅读(四)网络
30 GroupSock(Port)——live555源码阅读(四)网络 30 GroupSock(Port)——live555源码阅读(四)网络 简介 Port类的定义 Port的构造与全局的 &l ...
- thinkphp的各种内部函数 D()、F()、S()、C()、L()、A()、I()
D() 加载Model类 M() 加载Model类 A() 加载Action类 L() 获取语言定义 C() 获取配置值 用法就是 C("这里填写在配置文件里数组的下标" ...
- IDEA 新建文件默认加入CVS
是要先add,不过可以设置创建的文件都默认 add的.修改默认值看下图:打开系统设置,找到 Version Control 设置选项: 在 When files are created 选项中选择第二 ...
- malloc/free与new/delete的区别
相同点:都可用于申请动态内存和释放内存 不同点:(1)操作对象有所不同.malloc与free是C++/C 语言的标准库函数,new/delete 是C++的运算符.对于非内部数据类的对象而言,光用m ...