题目链接: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. [ PyQt入门教程 ] PyQt5基本控件使用:消息弹出、用户输入、文件对话框

    本文主要介绍PyQt界面实现中常用的消息弹出对话框.提供用户输入的输入框.打开文件获取文件/目录路径的文件对话框.学习这三种控件前,先想一下它们使用的主要场景: 1.消息弹出对话框.程序遇到问题需要退 ...

  2. UR机器人通信--上位机通信(python)

    一.通信socket socket()函数 Python 中,我们用 socket()函数来创建套接字,语法格式如下: socket.socket([family[, type[, proto]]]) ...

  3. Activity 使用详解

    极力推荐文章:欢迎收藏 Android 干货分享 阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android 本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以 ...

  4. CentOS 7服务器安装brook和bbr加速

    一.安装Brook 执行一键部署脚本 $ wget -N --no-check-certificate wget -N --no-check-certificate https://raw.githu ...

  5. 6、高级的数组的复制(test4.java)

    这里指的高级,并不是过么高大上,而是说我们可以调用系统函数,直接对数组进行复制,并且这个函数的强大并不止局限于,对数组的复制,而且可以对数组进行截取,在指定位置插入或删除某个元素. 本篇只介绍数组的复 ...

  6. gRPC【RPC自定义http2.0协议传输】

    gRPC 简介 gRPC是由Google公司开源的高性能RPC框架. gRPC支持多语言 gRPC原生使用C.Java.Go进行了三种实现,而C语言实现的版本进行封装后又支持C++.C#.Node.O ...

  7. 以股票案例入门基于SVM的机器学习

    SVM是Support Vector Machine的缩写,中文叫支持向量机,通过它可以对样本数据进行分类.以股票为例,SVM能根据若干特征样本数据,把待预测的目标结果划分成“涨”和”跌”两种,从而实 ...

  8. 【模板】珂朵莉树(ODT)(Codeforces 896C Willem, Chtholly and Seniorious)

    题意简述 维护一个数列,支持区间加,区间赋值,区间求第k小,区间求幂和 数据随机 题解思路 ODT是一种基于std::set的暴力数据结构. 每个节点对应一段区间,该区间内的数都相等. 核心操作spl ...

  9. Android8.1 MTK平台 截屏功能分析

    前言 涉及到的源码有 frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java vend ...

  10. 8.6 day27 网络编程 osi七层协议 Time模块补充知识 TCP协议

    Time模块补充知识 date和datetime区别是什么? date 就是年月日 datetime就是年月时时分秒 以下代码为什么会报错? import json from datetime imp ...