Online JudgeProblem SetAuthorsOnline ContestsUser
Web Board
Home Page
F.A.Qs
Statistical Charts
Problems
Submit Problem
Online Status
Prob.ID:
Register
Update your info
Authors ranklist
Current Contest
Past Contests
Scheduled Contests
Award Contest
User ID:
Password:
  Register

发个题解

Posted by jxufebingone at 2014-08-22 14:12:47 on Problem 1417
/************************************************************************/
/* 
提供测试数据:
11 9 7
6 12 no
4 8 yes
3 12 yes
5 9 no
6 11 yes
6 5 no
15 4 yes
16 15 yes
10 3 no
6 16 no
2 6 no
6 2 4
1 1 yes
2 3 yes
3 4 yes
4 5 no
5 6 yes
6 6 yes
3 3 2
1 2 no
3 4 yes
3 5 no

0 0 0

输出:

no
5
6
end
no


 */
/************************************************************************/
#include<math.h>
#include<stdio.h>  
#include<string.h>
#include<algorithm>
#define maxn 700
using namespace std;
int N,M,T,X,Y;
int ans;
int parent[maxn];
int relate[maxn];
char str[10];
int indata[2*maxn];
int dp[maxn][maxn];
int path[maxn][maxn];
int setname[maxn];
int find(int *parent,int k);
int backpack()
{
	int i,j,k,t,m;
	k=0;
	memset(dp,0,sizeof(dp));
	memset(path,0,sizeof(path));
	memset(indata,0,sizeof(indata));
	memset(setname,0,sizeof(setname));
	for(i=1;i<=X+Y;i++)
		find(parent,i);//再压缩一下路径
	for(i=1;i<=X+Y;i++)
		if(parent[i]==-1)
			setname[k++]=i;//得到各个集合,以根结点标识
	for(i=0;i<k;i++)
		for(j=indata[2*i]=1;j<=X+Y;j++)//<span style="color:#FF0000;">根与自身定为同类</span>
			if(parent[j]==setname[i])
				if(relate[j]==0)
					indata[2*i]++;//统计与自己同类的元素个数
				else
					indata[2*i+1]++;
	dp[0][indata[0]]++;path[0][indata[0]]=1;
	dp[0][indata[1]]++;path[0][indata[1]]=2;
	/*for(i=0;i<k;i++)
		printf("%d,%d\n",indata[i*2],indata[i*2+1]);*/
/*
这里WA了好久,之前用无限背包的想法,dp设为一维数组。但是这里不同的是背包为两种重量而非之前选或不选。
所以不能用。否则会计算重叠。
这里要求是全部的集合都使用完后再判断(因为每个集合中都是与自己相反或相同的类别)。
*/
      &nbsp;for(i=1;i<k;i++)
		for(j=X;j>=0;j--)
		{

			if(j>=indata[2*i] && dp[i-1][j-indata[2*i]] )
				dp[i][j]+=dp[i-1][j-indata[2*i]],path[i][j]=1;
			if(j>=indata[2*i+1] && dp[i-1][j-indata[2*i+1]] )
				dp[i][j]+=dp[i-1][j-indata[2*i+1]],path[i][j]=2;
		}
	if(dp[k-1][X]!=1)
		return 0;
	ans=0;
	m=X;
	i=k-1;
	while(i>=0)
	{
		if(path[i][m]==1)
			t=0,m=m-indata[2*i];
		else
			t=1,m=m-indata[2*i+1];
		for(j=1;j<=X+Y;j++)
			if(parent[j]==setname[i] || j==setname[i])
				if(relate[j]==t)
					dp[0][ans++]=j;		
		i--;
	}
	sort(dp[0],dp[0]+ans);
	return 1;
		
		
}
void swap(int *a,int *b)
{
	int t;
	t=*a;
	*a=*b;
	*b=t;
}
int find(int *parent,int k)
{
	if(parent[k]==-1)
		return k;
	int t=parent[k];
	parent[k]=find(parent,parent[k]);
	relate[k]=(relate[k]+relate[t])%2;//并查集的高级应用,即每次合并都得到该点与父节点的关系。
	return parent[k];
}
int main()
{
	int i;
	int e,r,ee,rr,cnt;
	//freopen("input.txt","r",stdin);
	//freopen("output.txt","w+",stdout);
	while(scanf("%d%d%d",&N,&X,&Y))
	{
		if(X==0 && Y==0 && N==0)
			break;
		memset(parent,-1,sizeof(parent));
		memset(relate, 0,sizeof(relate));
		for(i=0;i<N;i++)
		{
			scanf("%d%d%s",&e,&r,str);
			if(r<e)swap(&r,&e);
			ee=find(parent,e);
			rr=find(parent,r);
			if(ee==rr)
				continue;//<span style="color:#FF0000;">若属于同一个集合则不合并,否则会有环路产生RE</span>
			if(str[0]=='y')
			{
				parent[rr]=ee,relate[rr]=(relate[e]+relate[r])%2;
			}
			else
				parent[rr]=ee,relate[rr]=(1+relate[r]+relate[e])%2;
		}
		if(X==Y)//若X,Y个数相等则没有可能
		{
			printf("no\n");
			continue;
		}
		if(backpack()==0)
			printf("no\n");
		else
		{
			for(i=0;i<ans;i++)
				printf("%d\n",dp[0][i]);
			printf("end\n");
		}
	} 
  return 0;  
}

Followed by:

Post your reply here:
User ID:
Password:
Title:

Content:

Home Page   Go Back  To top


All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator