| ||||||||||
| Online Judge | Problem Set | Authors | Online Contests | User | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest | |||||||||
发个题解/************************************************************************/
/*
提供测试数据:
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设为一维数组。但是这里不同的是背包为两种重量而非之前选或不选。
所以不能用。否则会计算重叠。
这里要求是全部的集合都使用完后再判断(因为每个集合中都是与自己相反或相同的类别)。
*/
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: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator