poj1417菜鸡的详细题解(希望能帮助到和我一样陷于本题的新手)
题意太麻烦就偷懒转载他人的题意。。。。。
题意转载自http://blog.csdn.net/acm_cxlove/article/details/7854526 by---cxlove
题目:给出p1+p2个人,其中p1个是好人,p2个是坏人。然后有一些关系 ,a说b是好人(坏人).其中没有矛盾的,判断是否有唯一解判断哪些人是好人,哪些人是坏人。
其中比较重要的是,好人总说真话,坏人总说假话。不需要判断矛盾。唯一解
http://poj.org/problem?id=1417
其中好人说真话,坏人说假话这点很重要。
那么如果一个人说另一个人是好人,那么如果这个人是好人,说明 对方确实是好人,如果这个是坏人,说明这句话是假的,对方也是坏人。
如果一个人说另一个人是坏人,那么如果这个人是好人,说明对方是坏人,如果这个是坏人,说明 对方是好人。
也就是如果条件是yes说明这两个是相同集合的,否则是两个不同的集合。
用r[i]表示i结点与根结点的关系,0为相同集合,1为不同集合。这是一个经典的并查集问题。
这样处理之后,还需要判断是否唯一
我们通过并查集,可以将所有人分为若干个集合,其中对于每一个集合,又分为两个集合(好人和坏人,但是不知道哪些是好人,哪些是坏人,我们只有相对关系)
接下来就是从所有大集合中的两个小集合取一个,组成好人集合,判断是否唯一。
背包问题,dp[i][j]表示前i个大集合,好人为j个的方案有多少种,或者dp[i][j]表示当前好人i个,坏人j个的情况有多少种
如果dp[cnt][p1]!=1说明方案不唯一,或者无解。
如果为1题目还需要输出方案,这点比较纠结。用后一种DP的时候WA了好多次,而这题又卡内存,不能开三维数组,其实可以两次DP解决。
后来采用前者DP,不断从dp[cnt][p1]往前递推,递推的结果也必须是某个前趋状态的dp值为1.
本代码改进了dp的空间大小,并由一c语言新手所编,其目的是为了帮助和我一样的新手理解和解决本题。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int f[1000],sex[1000];//0代表同类,1代表不同类;
int sum[2][1000];//记录人数
int cnt,mark[1000][1000];//记录取的是哪个小集合
int w[2][1000],p[1000];//相当于背包问题中的提取出重量
int dp[2][1000];
int ans[1000];//记录答案
int init(int n)
{
int i;
memset(sex,0,sizeof(sex));
for(i=1;i<=n;i++)
{
f[i]=i;
sum[0][i]=1;//相同数
sum[1][i]=0;//不同数
}
}
int find(int x)
{
if(x==f[x])
return x;
int t=f[x];
f[x]=find(f[x]);//找爷爷
sex[x]=sex[t]^sex[x];//通过x与x父亲确定x与x爷爷的关系
return f[x];
}
int Union(int x,int y,int k)
{
int fx=find(x);
int fy=find(y);
if(fx==fy)
return 0;
f[fy]=fx;
sex[fy]=sex[x]^sex[y]^k;//更新fy与fx的关系
sum[0][fx]+=sum[sex[fy]^0][fy];//将fy的人数并到fx中
sum[1][fx]+=sum[sex[fy]^1][fy];
return 0;
}
int main()
{
int n,p1,p2;
while(scanf("%d%d%d",&n,&p1,&p2)!=EOF&&(n+p1+p2))
{
int i,j,k;
int x,y;
char a[5];
int p0=p1+p2;
init(p0);//初始数据
for(i=0;i<n;i++)
{
scanf("%d%d%s",&x,&y,a);
if(a[0]=='n')
Union(x,y,1);
else if(a[0]=='y')
Union(x,y,0);
}
cnt=0;
for(i=1;i<=p0;i++)//提取出各个大集合 (每个大集合里有两个小集合)
{
if(find(i)==i)
{
w[0][cnt]=sum[0][i];
w[1][cnt]=sum[1][i];
p[cnt]=i;
cnt++;
}
}
int b1,b2;
b1=0;
b2=1;
memset(mark,0,sizeof(mark));
memset(dp,0,sizeof(dp));
dp[0][0]=1;//最基本的一种情况
for(i=0;i<cnt;i++)
{
int t;
memset(dp[b2],0,sizeof(dp[b2]));//初始化下一种状态
for(t=p1;t>=w[0][i];t--)//dp思想,求第i个集合时取t个人有几种情况 ,如果看不懂请先百度背包九讲理解01背包的解决思路。
{
if(dp[b1][t-w[0][i]])
{
dp[b2][t]+=dp[b1][t-w[0][i]];
//printf("Wdp[%d][%d]=%d\n",b2,t,dp[b2][t]);
mark[i][t]=0;//记录取的是哪个小集合里的
}
}
for(t=p1;t>=w[1][i];t--)
{
if(dp[b1][t-w[1][i]])
{
dp[b2][t]+=dp[b1][t-w[1][i]];
//printf("Qdp[%d][%d]=%d\n",b2,t,dp[b2][t]);
mark[i][t]=1;
}
}
b1=b1^1;
b2=b2^1;
}
k=0;
if(dp[cnt%2][p1]!=1)
printf("no\n");
else
{
for(i=cnt-1;i>=0;i--)
{
int cur;
cur=mark[i][p1];//看取的是i的哪个小集合
for(j=1;j<=p0;j++)
{
if(find(j)==p[i]&&cur==sex[j])//找到i个大集合的元素并判断是哪个小集合
{
ans[k++]=j;
}
}
if(cur==0)//更新p1以便找寻是下一个大集合的小集合
p1-=w[0][i];
else
p1-=w[1][i];
}
sort(ans,ans+k);
for(i=0;i<k;i++)
printf("%d\n",ans[i]);
printf("end\n");
}
}
return 0;
}
poj1417菜鸡的详细题解(希望能帮助到和我一样陷于本题的新手)的更多相关文章
- 菜鸡谈OO 第一单元总结
“OOP永远是我的好朋友爸爸!” ——来自某无能狂怒的菜鸡 身处在OO的第一个摸鱼黄金周中的我,感觉到了巨大的满足感.如果写博客这种充满意义的事情可以代替我们亲爱的作业,那么我提议每周来两个:)下面开 ...
- ACM菜鸡退役帖——ACM究竟给了我什么?
这个ACM退役帖,诸多原因(一言难尽...),终于决定在我大三下学期开始的时候写出来.下面说两个重要的原因. 其一是觉得菜鸡的ACM之旅没人会看的,但是新学期开始了,总结一下,只为了更好的出发吧. 其 ...
- 记录一下寄几个儿的greendao数据库升级,可以说是非常菜鸡了嗯
之前使用的greendao数据库存储服务器所有的历史推送消息,但是后来消息需要加几个新的字段 举个栗子,比如要新增红色框住的字段到数据库中: 本仙女作为一只思想成熟的菜鸡,当然是加了字段就赶紧重新往里 ...
- Codeforces Round #405 (rated, Div. 2, based on VK Cup 2017 Round 1) 菜鸡只会ABC!
Codeforces Round #405 (rated, Div. 2, based on VK Cup 2017 Round 1) 全场题解 菜鸡只会A+B+C,呈上题解: A. Bear and ...
- Html菜鸡大杂烩
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- HDU 2064 菜鸡第一次写博客
果然集训就是学长学姐天天传授水铜的动态规划和搜索,今天讲DP由于困意加上面瘫学长"听不懂就是你不行"的呵呵传授,全程梦游.最后面对连入门都算不上的几道动态规划,我的内心一片宁静,甚 ...
- 菜鸡谈OO 第二单元总结
“欢迎来到(玄学)多线程的新世界” Homework1 单部傻瓜电梯调度 Part1 多线程设计策略 第一次学到了线程这个概念,与之前的编程体验大有不同.最大的区别在于从原本的线性发生程序变成了多个行 ...
- 一个数学不好的菜鸡的快速沃尔什变换(FWT)学习笔记
一个数学不好的菜鸡的快速沃尔什变换(FWT)学习笔记 曾经某个下午我以为我会了FWT,结果现在一丁点也想不起来了--看来"学"完新东西不经常做题不写博客,就白学了 = = 我没啥智 ...
- $\rm{NOIP}$前的模拟题整理·菜鸡互啄篇
嗯,打算整理一下我们机房菜鸡互啄中比较不错的题-- 大概情况就是每个人出三道题,然后互测这种感觉-- 至于某些Y姓基佬.Z姓基佬偷偷出原题--就不说了233 嗯,剩下的就先\(magpie\)着吧23 ...
随机推荐
- HDU 4315 Climbing the Hill [阶梯Nim]
传送门 题意: 和上题基本一样:山顶可以有多人,谁先把king放到山顶谁就胜 并不太明白 #include <iostream> #include <cstdio> #incl ...
- BZOJ 1801: [Ahoi2009]chess 中国象棋 [DP 组合计数]
http://www.lydsy.com/JudgeOnline/problem.php?id=1801 在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮. 请问有多少种放 ...
- WPF Effect 造成的字体模糊
WPF 里面有个Effect ,暂且可以理解为 "特效" 分类. 但是有时候使用不恰当,容易出现各种毛病. 例如: 代码如下: <StackPanel HorizontalA ...
- 使用IntelliJ IDEA(PHPStorm)和xdebug在firefox、chrome中远程调试PHP
很多PHP程序员都习惯于使用echo.var_dump和exit来中断和调试web应用程序,本文主要介绍结合xdebug.IntelliJ IDEA.Firefox/chrome/IE来远程调试PHP ...
- 时间序列数据库rrd启动
然后执行启动定时任务目录:etc/crontab SHELL=/bin/bashPATH=/sbin:/bin:/usr/sbin:/usr/binMAILTO=rootHOME=/ # For de ...
- ps通道抠章
1. 打开图片 2. 使用椭圆形选框工具,选择章所在范围(ALT+SHITF+鼠标左键) 3.复制图层(CTRL+J)为图层1,隐藏背景 4.进入通道,选择对比度最大的通道,复制通道副本 5.反选(C ...
- dedecms data文件夹外迁
出于网站安全考虑,我们一般要把data文件夹迁移到网站根目录外面. dedecms data文件夹外迁方法: 1. 修改首页文件中配置文件路径 打开/index.php,把代码 if(!file_ex ...
- js到底new了点啥
在最开始学习js的时候,我看书上写着,创建一个数组,一个对象通常使用new,如下: var arr=new Array(),//arr=[] obj=new Object();//obj={} 到了后 ...
- 卷积神经网络(CNN)在句子建模上的应用
之前的博文已经介绍了CNN的基本原理,本文将大概总结一下最近CNN在NLP中的句子建模(或者句子表示)方面的应用情况,主要阅读了以下的文献: Kim Y. Convolutional neural n ...
- 如何写出测不出bug的测试用例
我们写测试用例的目的是为了能够整理思路,把要测试的地方列出来,做为知识的积淀,用例可以交给其他测试人员执行,或者是跟需求提出者进行讨论,对用例进行补充和修改. 理论上用例写的越多,越容易发现bug.但 ...