(带权并查集+dp)POJ1417 True Liars

POJ1417 True Liars

题意&思路:

一个写了三天的题。
一个岛上存在p1个好人和p2个坏人。Akira可以询问n个问题,每个问题由两个编号x,y和一个字符串a(yes或者no)组成。好人会说实话,坏人会说假话。每次询问表示x如果想让你认为y是好人就会回答yes。问是否能够得到好人的编号。
加权并查集+dp。
加权并查集并不难想,我们不难发现回答yes的是同类,no的是异类。我们用权值0表示同类,1表示异类,每次区间合并和路径压缩的时候可以进行取模运算,也可以考虑异或运算。
这样我们就把岛上的人分成了多个集合,每个集合包含两种人。这时候我们采用背包问题的解法。因为每个集合都必须选一类人,所以我们要用二维数组(用一维一直卡,因为一维不能表示用了多少组,所以不能确定有没有选某个集合)。
状态转移方程为dp[i][j]+=dp[i-1][j-a[i][0/1]]。i表示选了几组,j表示选了多少个人,dp的值为方案数。
最后看dp[tot][p1]是否等于1,tot为集合的总数。当且仅当方案数为1的时候才能确定编号。
编号的输出(又卡了好长时间),用倒推的方式,因为dp[tot][p1]的方案数为1,所以能使之成立的dp[i-1][p1-a[i][0/1]]的方案数也只能为1。
然后排序输出就好了。可是鬼迷心窍的多输出了yes。
以及初始化,初始化,初始化。

代码:

#include<map>
#define ll long long
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<ctype.h>
#include<queue>
#include<set>
#include<stack>
#include<cmath>
const int N=1e3+10;
const int mod=1e7+9;
const int maxn=0x3f3f3f3f;
const int minn=0xc0c0c0c0;
const int inf=99999999;
using namespace std;
int fa[N],sum[N],dp[N][N],a[N][2],ans[N];
vector<int> son[N][2];
map<int,int> maze;
int find(int x)
{
	if(x!=fa[x])
	{
		int t=fa[x];
		fa[x]=find(fa[x]);
		sum[x]^=sum[t];
	}
	return fa[x];
}
void add(int u,int v,int w)
{
	int t1=find(u),t2=find(v);
	if(t1!=t2)
	{
		fa[t1]=t2;
		sum[t1]=sum[u]^sum[v]^w;
	}
	return;
}
int main()
{
	int n,p1,p2;
	while(~scanf("%d%d%d",&n,&p1,&p2) && n+p1+p2)
	{
		int i,j;
		memset(dp,0,sizeof(dp));
		memset(a,0,sizeof(a));
		memset(ans,0,sizeof(ans));
		maze.clear();
		for(i=1;i<=p1+p2;i++)
		{
			fa[i]=i;
			sum[i]=0;
			for(j=0;j<=1;j++)
				son[i][j].clear();
		}
		while(n--)
		{
			int x,y,w;
			char s[5];
			scanf("%d%d%s",&x,&y,s);
			if(x==y)	continue;
			if(!strcmp(s,"yes"))	
				w=0;
			else	
				w=1;
			add(x,y,w);
		}
		int tot=0;
		for(i=1;i<=p1+p2;i++)
		{
			int t=find(i);
			if(maze[t]==0)	maze[t]=++tot;
			a[maze[t]][sum[t]^sum[i]]++;
			son[maze[t]][sum[t]^sum[i]].push_back(i);
		}
		dp[0][0]=1;
		for(i=1;i<=tot;i++)
			for(j=p1;j>=0;j--)
			{
				if(j>=a[i][0])
					dp[i][j]+=dp[i-1][j-a[i][0]];
				if(j>=a[i][1])
					dp[i][j]+=dp[i-1][j-a[i][1]];
				
			}
		int l=p1,len=0;
		if(dp[tot][p1]==1)
		{
			for(i=p1+p2;i>=1;i--)
				if(dp[i-1][l-a[i][0]]==1)
				{
					l-=a[i][0];
					for(j=0;j<son[i][0].size();j++)
						ans[++len]=son[i][0][j]; 
				}
				else if(dp[i-1][l-a[i][1]]==1)
				{
					l-=a[i][1];
					for(j=0;j<son[i][1].size();j++)
						ans[++len]=son[i][1][j];
				}		
			sort(ans+1,ans+len+1);
			for(i=1;i<=len;i++)
				printf("%d\n",ans[i]);
			printf("end\n");
		}
		else
			printf("no\n");
	}
	return 0;
}

发布了78 篇原创文章 · 获赞 0 · 访问量 1397

猜你喜欢

转载自blog.csdn.net/Z7784562/article/details/104025895