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)表示前 ...
随机推荐
- Js面向对象构造函数继承
构造函数继承 <!-- 创建构造函数 --> function Animal(){ this.species= '动物'; } function Dog(name,color){ this ...
- Docker Toolbox安装
公司最近搭建docker环境,其中会遇到一些问题,在这里记录一下. 先来了解一下docker 一.基本概念 1.Docker中基本概念镜像(Image) 提到镜像,有对操作系统有一定认知的都知道,镜像 ...
- Docker——理解好镜像和容器的关系
关注公众号,大家可以在公众号后台回复“博客园”,免费获得作者 Java 知识体系/面试必看资料. 镜像也是 docker 的核心组件之一,镜像时容器运行的基础,容器是镜像运行后的形态.前面我们介绍了 ...
- 浅谈单例模式及其java实现
单例模式是23种设计模式中比较简单的一种,在此聊一下单例模式. 1.什么是设计模式? 对于没有接触过设计模式的人来说,一听到设计模式这四个字就觉得这个东西很高深莫测,一下子就对这个东西产生了恐惧感,其 ...
- 4如何用PHP给MySQL数据库添加记录
首先连接数据库(依旧用第二篇的方法) 假设数据库表里只有id,name,email三列 添加以下代码 $inputemail=写你要的email;$inputname=写你要的name;//先设定你要 ...
- 使用mybatis实现分页查询示例代码分析
*******************************************分页查询开始*************************************************** ...
- Ubuntu 16.04 安装 SVN-Client (RaabitVCS)
1.添加源 sudo add-apt-repository ppa:rabbitvcs/ppa 2. 更新源 sudo apt-get update 3.安装依赖库 sudo apt-get inst ...
- DC-2靶机
DC-2 靶机获取:http://www.five86.com/ 靶机IP:192.168.43.197(arp-scan l) 攻击机器IP:192.168.43.199 在hosts文件里添加:1 ...
- javaScript基础-0 javascript概述
一.简介 javaScript一种面向web的编程语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早 ...
- 康托(Cantor)展开
直接进入正题. 康托展开 Description 现在有"ABCDEFGHIJ”10个字符,将其所有的排列中按字典序排列,给出任意一种排列,说出这个排列在所有的排列中是第几小的? Input ...