poj 1417 True Liars(并查集+背包dp)
题目链接:http://poj.org/problem?id=1417
题意:就是给出n个问题有p1个好人,p2个坏人,问x,y是否是同类人,坏人只会说谎话,好人只会说实话。
最后问能否得出全部的好人编号是多少并且从小到大输出
由于好人只说实话坏人只说谎话。一个人说另一个人不是同类,如果他是好人那么另外一个人就是坏人,如果这是坏人那么另外一个人就是也是坏人
一个人说另一个人是同类,如果他是好人那么另一个人就是好人,如果这时坏人那么另一个人也是好人。
所以这种关系正好方便枚举,因为要么这群人是好人要么就是坏人,一旦关系定了只要确定是好人还是坏人就行了。
但是这题用枚举不行。怎么确定不了所有好人的个数,那是当满足条件的情况没有或者大于1个如果用枚举那就太复杂了。
于是可以想到用背包来解决这类问题。背包dp[i][j]来存储前i个关系中得到好人个数为j的有多少个。
为什么会想到用背包来解决这个问题呐?因为01背包就是枚举总结的一种优化,01背包可以保存达到方案的最大权值或者最大个数
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cstdio>
using namespace std;
const int M = 1010;
int n , p1 , p2 , f[M] , root[M];
void init() {
for(int i = 1 ; i <= p1 + p2 ; i++) {
f[i] = i , root[i] = 0;
}
}
int find(int x) {
if(x == f[x])
return x;
int tmp = find(f[x]);
root[x] = (root[x] + root[f[x]]) % 2;
return f[x] = tmp;
}
bool vis[M];
vector<int>vc[M][3];
int dp[M][M] , v[M][3] , pre[M][M];
int main() {
int x , y;
char cp[10];
while(scanf("%d%d%d" , &n , &p1 , &p2)) {
init();
int tmp;
if(n == 0 && p1 == 0 && p2 == 0)
break;
for(int i = 0 ; i < n ; i++) {
scanf("%d%d%s" , &x , &y , cp);
int a = find(x) , b = find(y);
if(cp[0] == 'y')
tmp = 0;
else
tmp = 1;
if(a != b) {
f[a] = b;
root[a] = (root[y] - root[x] + tmp + 2) % 2;
}
}
int cnt = 1;
for(int i = 0 ; i < M ; i++) {
vc[i][0].clear();
vc[i][1].clear();
v[i][0] = 0;
v[i][1] = 0;
}
memset(vis , false , sizeof(vis));
for(int i = 1 ; i <= p1 + p2 ; i++) {
if(!vis[i]) {
int ro = find(i);
for(int j = i ; j <= p1 + p2 ; j++) {
int ro2 = find(j);
if(ro == ro2) {
vis[j] = true;
vc[cnt][root[j]].push_back(j);
v[cnt][root[j]]++;
}
}
cnt++;
}
}
for(int i = 0 ; i < cnt ; i++) {
for(int j = 0 ; j <= p1 ; j++) {
dp[i][j] = 0;
}
}
dp[0][0] = 1;
for(int i = 1 ; i < cnt ; i++) {
for(int j = p1 ; j >= 0 ; j--) {
if(j >= v[i][0] && dp[i - 1][j - v[i][0]]) {
dp[i][j] += dp[i - 1][j - v[i][0]];
pre[i][j] = j - v[i][0];
}
if(j >= v[i][1] && dp[i - 1][j - v[i][1]]) {
dp[i][j] += dp[i - 1][j - v[i][1]];
pre[i][j] = j - v[i][1];
}
}
}
if(dp[cnt - 1][p1] != 1) {
printf("no\n");
continue;
}
else {
vector<int>ans;
ans.clear();
int gg = p1;
int temp;
for(int i = cnt - 1 ; i >= 1 ; i--) {
temp = gg - pre[i][gg];
gg = pre[i][gg];
if(v[i][0] == temp) {
int len = vc[i][0].size();
for(int j = 0 ; j < len ; j++) {
ans.push_back(vc[i][0][j]);
}
}
else {
int len = vc[i][1].size();
for(int j = 0 ; j < len ; j++) {
ans.push_back(vc[i][1][j]);
}
}
}
sort(ans.begin() , ans.end());
int len = ans.size();
for(int i = 0 ; i < len ; i++) {
printf("%d\n" , ans[i]);
}
printf("end\n");
}
}
return 0;
}
poj 1417 True Liars(并查集+背包dp)的更多相关文章
- poj1417 True Liars[并查集+背包]
有一点小转化的题,在设计dp状态时还是有点费脑筋的. 地址. 依题意,首先可以知道肯定要扩展域的并查集(明摆着的嘛).一个"好人"域,一个"坏人"域,每句话分两 ...
- POJ1417 True Liars —— 并查集 + DP
题目链接:http://poj.org/problem?id=1417 True Liars Time Limit: 1000MS Memory Limit: 10000K Total Submi ...
- POJ 1417 True Liars
题意:有两种人,一种人只会说真话,另一种人只会说假话.只会说真话的人有p1个,另一种人有p2个.给出m个指令,每个指令为a b yes/no,意思是,如果为yes,a说b是只说真话的人,如果为no,a ...
- POJ 1417 - True Liars - [带权并查集+DP]
题目链接:http://poj.org/problem?id=1417 Time Limit: 1000MS Memory Limit: 10000K Description After having ...
- 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(带权并查集+背包DP+路径回溯)
题目链接:http://poj.org/problem;jsessionid=8C1721AF1C7E94E125535692CDB6216C?id=1417 题意:有p1个天使,p2个恶魔,天使只说 ...
- hdu 4514 并查集+树形dp
湫湫系列故事——设计风景线 Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Tot ...
- POJ - 1417 并查集+背包
思路:很简单的种类并查集,利用并查集可以将所有的人分成几个集合,每个集合又分为好人和坏人集合,直接进行背包dp判断有多少种方法可以在取了所有集合并且人数正好凑足p1个好人的方案.dp(i, j)表示前 ...
随机推荐
- c#小灶——初识c#
提到c#,就不得不说.net,.net是微软开发的一个平台,简单来说,在这个平台上,可以编写.运行程序.可能很多人觉得这个平台离我们很遥远,其实不然,这个平台就一直在我们的windows操作系统里,默 ...
- HTML 第4章初始CSS3
什么是CSS? CSS全称为层叠样式表,通常又称为风格样式表. 引用CSS样式: 语法: <h1 styske="color:red;">style属性的应用</ ...
- Hadoop 系列(二)—— 集群资源管理器 YARN
一.hadoop yarn 简介 Apache YARN (Yet Another Resource Negotiator) 是 hadoop 2.0 引入的集群资源管理系统.用户可以将各种服务框架部 ...
- 4、一个打了鸡血的for循环(增强型for循环)
对于循环,我们大家应该都不陌生,例如do-while循环,while循环,for循环,今天给大家介绍一个有趣的东西——打了鸡血的for循环(增强型for循环). 首先看代码,了解一下for循环的结构: ...
- Elasticsearch索引增量统计及定时邮件实现
0.需求 随着ELKStack在应用系统中的数据规模的急剧增长,每天千万级别数据量(存储大小:10000000*10k/1024/1024=95.37GB,假设单条数据10kB,实际远大于10KB)的 ...
- Go中的函数和闭包
函数参数和返回值的写法 如果有多个参数是同一个类型,可以简略写: func testReturnFunc(v1,v2 int)(int,int) { x1 := 2 * v1 x2 := 3 * v2 ...
- Zookeeper的命令行操作(三)
Zookeeper的命令行操作 1. ZooKeeper服务命令 在准备好相应的配置之后,可以直接通过zkServer.sh 这个脚本进行服务的相关操作 1. 启动ZK服务: sh bin/zkSer ...
- CodeForces 15D Map
洛谷题目页面传送门 & CodeForces题目页面传送门 题意见洛谷里的翻译.(注意翻译里有错误,应该是优先选上面的矩阵,在同一行的优先选左边的矩阵) 这题一看就会做啊 (以下设大矩阵是\( ...
- while 的循环遍历 分享心得
while 基本循环体 1.while while 条件: 循环体 2.while else while 条件: 循环体 else:#如果while条件结果为假 不执行循环体 直接执行else 代码块 ...
- 自定义Dialog---实现优美对话框
PS:自定义dialog,一些系统的dialog已经不能满足开发人员的需求了,所以,我们需要自定义一个属于并且适合自己项目的对话框,无论是颜色还是功能需求上都是和自己的项目紧密相关的,一些系统的对话框 ...