题目链接: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)的更多相关文章

  1. poj1417 True Liars[并查集+背包]

    有一点小转化的题,在设计dp状态时还是有点费脑筋的. 地址. 依题意,首先可以知道肯定要扩展域的并查集(明摆着的嘛).一个"好人"域,一个"坏人"域,每句话分两 ...

  2. POJ1417 True Liars —— 并查集 + DP

    题目链接:http://poj.org/problem?id=1417 True Liars Time Limit: 1000MS   Memory Limit: 10000K Total Submi ...

  3. POJ 1417 True Liars

    题意:有两种人,一种人只会说真话,另一种人只会说假话.只会说真话的人有p1个,另一种人有p2个.给出m个指令,每个指令为a b yes/no,意思是,如果为yes,a说b是只说真话的人,如果为no,a ...

  4. POJ 1417 - True Liars - [带权并查集+DP]

    题目链接:http://poj.org/problem?id=1417 Time Limit: 1000MS Memory Limit: 10000K Description After having ...

  5. POJ 1417 True Liars(种类并查集+dp背包问题)

    题目大意: 一共有p1+p2个人,分成两组,一组p1,一组p2.给出N个条件,格式如下: x y yes表示x和y分到同一组,即同是好人或者同是坏人. x y no表示x和y分到不同组,一个为好人,一 ...

  6. POJ1417 True Liars 并查集 动态规划 (种类并查集)

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ1417 题意概括 有一群人,p1个好人,p2个坏人. 他们说了n句话.(p1+p2<=600,n ...

  7. poj1417(带权并查集+背包DP+路径回溯)

    题目链接:http://poj.org/problem;jsessionid=8C1721AF1C7E94E125535692CDB6216C?id=1417 题意:有p1个天使,p2个恶魔,天使只说 ...

  8. hdu 4514 并查集+树形dp

    湫湫系列故事——设计风景线 Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tot ...

  9. POJ - 1417 并查集+背包

    思路:很简单的种类并查集,利用并查集可以将所有的人分成几个集合,每个集合又分为好人和坏人集合,直接进行背包dp判断有多少种方法可以在取了所有集合并且人数正好凑足p1个好人的方案.dp(i, j)表示前 ...

随机推荐

  1. 【vue】------ 路由创建 ------ 【William】

    路由常用的配置项: path:路由请求的路径 component:路由匹配成功后需要渲染的组件或者页面 tag:改变组件内部渲染的元素 假设组件内部渲染的是a标签 tag="li" ...

  2. Spring的数据库编程浅入浅出——不吹牛逼不装逼

    Spring的数据库编程浅入浅出——不吹牛逼不装逼 前言 上文书我写了Spring的核心部分控制反转和依赖注入,后来又衔接了注解,在这后面本来是应该写Spring AOP的,但我觉得对于初学者来说,这 ...

  3. CodeGlance右侧窗口缩略图消失不见

    说明下问题,idea中的CodeGlance插件会在右侧显示缩略图,可以快速定位代码.今天遇到个问题升级了插件后右侧窗口消失.经过卸载插件,重启,reset一系列操作后还是没能恢复. 能去搜索引擎搜索 ...

  4. loadrunner中的ie浏览器无法使用

    我的loadrunner是12.55版本的,windows10系统 在我们学习loadrunner的过程中,会出现下面一个问题: 在录制脚本时,loadrunner中的ie浏览器无法使用处于飘红状态. ...

  5. Redis——发布和订阅

    发布与订阅(又称pub/sub),订阅者(listener)负责订阅频道(channel),发送者(publisher)负责向频道发送二进制字符串消息(binary string message).每 ...

  6. Redis——基础使用

    Redis总体介绍: Redis特性 Redis(REmote DIctionary Server),是一个开源的内存数据库 持久化:RDB.AOF 主备复制 丰富的数据结构 Lua脚本.事务 Red ...

  7. final,权限,引用类型数据

    1. final关键字 1.概述 为了避免子类出现随意改写父类的情况,java提供了关键字final,用于修饰不可改变内容 final:不可改变,可以修饰类,方法和变量 类:被修饰的类,不能用于继承 ...

  8. Java 从入门到进阶之路(一)

    写在前面:从本片文章开始,将记录自己学习 Java 的点滴路程,目标定的并不是让自己成为一个 Java 高手,而是让自己多掌握一门语言,使自己的知识面更广一些,在学习 Java 的过程中如有不对的地方 ...

  9. rwcheck:为嵌入式设备设计的读写压测工具

    我设计的一款读写压测工具,开源在我的github仓库 rwcheck是一个对嵌入式设备进行读写压测的工具 什么是rwcheck 正如其名,rwcheck工具用于读写压测.它是什么工作原理呢?为什么要用 ...

  10. idea(java)实用开发插件

    Idea常用的插件: mybatisX,      ----------------  (Alt + enter) codeGlace, Lombok, sonarlint, translation, ...