思路:很简单的种类并查集,利用并查集可以将所有的人分成几个集合,每个集合又分为好人和坏人集合,直接进行背包dp判断有多少种方法可以在取了所有集合并且人数正好凑足p1个好人的方案。dp(i, j)表示前i和集合有j个好人的方案,如果dp(n, p1)不等于1说明方案不止一种或则根本不存在。注意在dp时,记录路径。

AC代码

#include <cstdio>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <cstring>
#include <utility>
#include <string>
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define eps 1e-10
#define inf 0x3f3f3f3f
#define PI pair<int, int>
typedef long long LL;
const int maxn = 600 + 5;
struct node{
	int par;
	int real;
}a[maxn];
int find(int x, int &r) {
	if(a[x].par == x) {
		r = x;
		return 0;
	}
	int w = find(a[x].par, r);
	a[x].par = r;
	return a[x].real = (a[x].real + w) % 2;
}
void unionset(int x, int y, int real) {
	int r1, r2;
	int rx = find(x, r1), ry = find(y, r2);
	if(r1 != r2) {
		a[r1].par = y;
		a[r1].real = (real + rx) % 2;
	}
}
int dp[maxn][maxn], pre[maxn][maxn], cnt[maxn][2];
bool vis[maxn];
vector<int>pep[maxn][2];

int main() {
	int n, p1, p2;
	while(scanf("%d%d%d", &n, &p1, &p2) == 3) {
		if(!p1 && !n && !p2) break;

		int num = p1 + p2;
		for(int i = 1; i <= num; ++i) {
			a[i].par = i;
			a[i].real = 0;
		}
		int x, y;
		char s[5];
		for(int i = 0; i < n; ++i) {
			scanf("%d%d%s", &x, &y, s);
			int  f = s[0] == 'y' ? 0 : 1;
			unionset(x, y, f);
		}
		memset(cnt, 0, sizeof(cnt));
		memset(vis, 0, sizeof(vis));
		int r, r1, c = 1;
		for(int i = 1; i <= num; ++i) {
			if(!vis[i]) {
				pep[c][0].clear();
				pep[c][1].clear();
				find(i, r);
				for(int j = i; j <= num; ++j) {
					int k = find(j, r1);
					if(r1 == r) {
						vis[j] = 1;
						pep[c][k].push_back(j);
						cnt[c][k]++;
					}
				}
				++c;
			}
		}
		memset(dp, 0, sizeof(dp));
		dp[0][0] = 1; //边界
		for(int i = 1; i < c; ++i)
			for(int j = p1; j >= 0; --j) {
				if(j-cnt[i][0] >= 0 && dp[i-1][j-cnt[i][0]]) {
					dp[i][j] += dp[i-1][j-cnt[i][0]];
					pre[i][j] = j - cnt[i][0];
				}
				if(j-cnt[i][1] >= 0 && dp[i-1][j-cnt[i][1]]) {
					dp[i][j] += dp[i-1][j-cnt[i][1]];
					pre[i][j] = j - cnt[i][1];
				}
			}
		if(dp[c-1][p1] != 1) {
			printf("no\n");
			continue;
		}
		vector<int>ans;
		ans.clear();
		int t = p1;
		for(int i = c-1; i >= 1; --i) {
			int tmp = t -  pre[i][t];
			if(cnt[i][0] == tmp) {
				for(int j = 0; j < pep[i][0].size(); ++j)
					ans.push_back(pep[i][0][j]);
			}
			else {
				for(int j = 0; j < pep[i][1].size(); ++j)
					ans.push_back(pep[i][1][j]);
			}
			t = pre[i][t];
		}
		sort(ans.begin(), ans.end());
		for(int i = 0; i < ans.size(); ++i) {
			printf("%d\n", ans[i]);
		}
		printf("end\n");
	}
	return 0;
} 

如有不当之处欢迎指出!

POJ - 1417 并查集+背包的更多相关文章

  1. POJ 1417 并查集 dp

    After having drifted about in a small boat for a couple of days, Akira Crusoe Maeda was finally cast ...

  2. poj 1417(并查集+简单dp)

    True Liars Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 2087   Accepted: 640 Descrip ...

  3. poj 1984 并查集

    题目意思是一个图中,只有上下左右四个方向的边.给出这样的一些边, 求任意指定的2个节点之间的距离. 就是看不懂,怎么破 /* POJ 1984 并查集 */ #include <stdio.h& ...

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

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

  5. poj1417 带权并查集 + 背包 + 记录路径

    True Liars Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 2713   Accepted: 868 Descrip ...

  6. poj 1797(并查集)

    http://poj.org/problem?id=1797 题意:就是从第一个城市运货到第n个城市,最多可以一次运多少货. 输入的意思分别为从哪个城市到哪个城市,以及这条路最多可以运多少货物. 思路 ...

  7. POJ 2492 并查集扩展(判断同性恋问题)

    G - A Bug's Life Time Limit:10000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u S ...

  8. POJ 2492 并查集应用的扩展

    A Bug's Life Time Limit: 10000MS Memory Limit: 65536K Total Submissions: 28651 Accepted: 9331 Descri ...

  9. POJ 3228 [并查集]

    题目链接:[http://poj.org/problem?id=3228] 题意:给出n个村庄,每个村庄有金矿和仓库,然后给出m条边连接着这个村子.问题是把所有的金矿都移动到仓库里所要经过的路径的最大 ...

随机推荐

  1. python_改变字符串中文本格式?

    案例: 某软件的日志文件,其中日期格式为year-moth-day: 2016-04-21 10:50:30 python 2014-05-22 10:50:30 python 2017-06-23 ...

  2. 剑指offfer:二维数组中的查找

    题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成这样一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 例如: 1    2  ...

  3. Inner Join and Left Join 与条件的结合

    在使用关系数据库时,表连接和对结果集的筛选是必不可少的查询技能,对于他们的用法你都搞清楚了么?请让我们一起来过一遍. 表创建与初始化: Inner Join 结果集: 对于Inner Join, 条件 ...

  4. linux 安装icu库

     先下载源码包并解压 然后安装 cd /icu/source ./configure --prefix=/usr/local/icu gmake make install  

  5. SQL Server错误严重性级别和异常处理

    关于SQL Server的错误严重性级别的说明,强烈认真看一下下面的两个链接 脱机帮助 ms-help://MS.SQLCC.v9/MS.SQLSVR.v9.zh-CHS/sqlerrm9/html/ ...

  6. 【转】5 Best Place to Learn Linux – Linux Tutorial Sites

    Linux have amazed every tech guy and make them curious to hands on Linux. Many of us not feel Linux ...

  7. 使用postMessage实现跨域 解决'Failed to execute 'postMessage' on 'DOMWindow''

    使用iframe+postMessage解决跨域问题,首先来过一遍其中的原理咯 原理: 发送方使用postMessage方法向接收方推送消息,第一个参数为推送的内容,第二个参数是允许被访问的域名: 接 ...

  8. 忽略node.js服务中favicon.icon的请求

    场景 一个最简单的node.js的http服务 const http = require('http'); const server = http.createServer(function(req, ...

  9. Trusted Execution Technology (TXT) --- 基本原理篇

    版权声明:本文为博主原创文章,未经博主允许不得转载. http://www.cnblogs.com/tsec/p/8409600.html 1. Intel TXT 介绍 TXT是Trusted Ex ...

  10. Pandas快速入门笔记

    我正以Python作为突破口,入门机器学习相关知识.出于机器学习实践过程中的需要,我快速了解了一下提供了类似关系型或标签型数据结构的Pandas的使用方法.下面记录相关学习笔记. 数据结构 Panda ...