题目链接: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. Spring MVC浅入浅出——不吹牛逼不装逼

    Spring MVC浅入浅出——不吹牛逼不装逼 前言 上文书说了Spring相关的知识,对Spring来了个浅入浅出,大家应该了解到,Spring在三层架构中主做Service层,那还有Web层,也就 ...

  2. C# Winform 自定义控件——竖着的Navbar

    效果: 描述: 这是一个可折叠的菜单导航,主要是由panel.picturebox.label完成,界面的颜色用来区分一下各个组合控件,便于调试. 首先,首先是ImageButton: 这个是由Pic ...

  3. 【TCP/IP】ICMP协议

    ICMP协议有两种报文: 1,查询报文 2,差错报文

  4. Salesforce LWC学习(三) import & export / api & track

    我们使用vs code创建lwc 时,文件会默认生成包含 template作为头的html文件,包含了 import LightningElement的 js文件以及对应的.js-meta.xml文件 ...

  5. 【游记】NOIP2019复赛

    声明 我的游记是一个完整的体系,如果没有阅读过往届文章,阅读可能会受到障碍. ~~~上一篇游记的传送门~~~ 前言 (编辑中)

  6. 线性分类 Linear Classification

    软分类:y 的取值只有正负两个离散值,例如 {0, 1} 硬分类:y 是正负两类区间中的连续值,例如 [0, 1] 一.感知机 主要思想:分错的样本数越少越好 用指示函数统计分错的样本数作为损失函数, ...

  7. 使用JMS接口接入WebSphere MQ消息

    在你的应用程序中利用IBM WebSphere MQ消息中间件提供Java消息服务开放接口. IBM WebSphere MQ(WMQ)是一套面向消息的中间件(message-oriented mid ...

  8. 搞懂Go垃圾回收

    本文主要介绍了垃圾回收的概念,Golang GC的垃圾回收算法和工作原理,看完本文可以让你对Golang垃圾回收机制有个全面的理解.由于本人不了解其他语言的GC,并未对比其他语言的垃圾回收算法,需要的 ...

  9. C/C++ 数据类型

    C/C++ 数据类型 C语言包含5个基本数据类型: void, integer, float, double, 和 char. 类型 描述 字节数 取值范围 void 空类型 1 int 整型 4 - ...

  10. 用gcc/g++编译winsock程序

    用gcc/g++编译winsock程序 D:\My\code>gcc -o getweb.exe getweb.c -lwin32socket 如果不加此句 -lwin32socket 编译会报 ...