解题思路
:当是yes时,两个是同一种类,当是no时,两个在不同种类。我开始做的时候把同一种类的分在一起,就形成了一些集合。然后想法是利用dp求出p的划分方法数,如果为1,就说明可以判断。但后来遇到了问题,因为有些集合是不能分在一起的。这样就出现了问题。于是我就按照有关系的人把他划分在一起,这也是种类划分方法,然后形成了一些集合,对p进行划分时,都是选取集合中的一种类型。如果选取方式只有一种,则说明可以判断,特别要主语p =0,q=0要单独考虑。 这里set[i][0]表示集合的根节点。set[i][1]表示和根节点同一种类的节点个数,set[i][2]表示和根节点不同种类的个数,set[i][3]表示选取集合中的哪一种。
- Source Code
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> using namespace std; const int MAXSIZE = 1005; struct People{ int father; int rank; int relation; }; People peo[MAXSIZE]; bool flag[MAXSIZE]; int set[MAXSIZE][4]; int f[MAXSIZE][MAXSIZE]; void init(int n){ for(int i = 1;i<=n;i++){ peo[i].father = i; peo[i].rank = 0; peo[i].relation = 0; flag[i] = false; for(int j =0;j<4;j++) set[i][j] = 0; } } int find(int x){ if(peo[x].father!=x){ int tmp = peo[x].father; peo[x].father = find(peo[x].father); peo[x].relation = (peo[tmp].relation+peo[x].relation)%2; } return peo[x].father; } void Union(int x,int y,int relation){ if(x == y) return ; if(peo[x].rank<peo[y].rank){ peo[x].father = y; peo[x].relation = relation; } else{ peo[y].father = x; peo[y].relation = relation; if(peo[x].rank == peo[y].rank){ peo[x].rank++; } } } int main(){ int n,p,q; while(scanf("%d%d%d",&n,&p,&q)==3&&(n|p|q)){ int x,y; char s[5]; init(p+q); while(n--){ scanf("%d%d%s",&x,&y,s); int a = find(x); int b = find(y); if(strcmp(s,"no")==0){ Union(a,b,(peo[x].relation+peo[y].relation+1)%2); } else{ Union(a,b,(peo[x].relation+peo[y].relation)%2); } } if(p == 0) { cout<<"end"<<endl; continue;} if(q == 0) { for(int i = 1;i<=p+q;i++){ cout<<i<<endl; } cout<<"end"<<endl; continue; } int k = 1; for(int i =1;i<=p+q;i++){ int tmp = find(i); if(flag[tmp] == false){ set[k][0]=find(i); if(peo[i].relation == 0) set[k++][1]++; else set[k++][2]++; flag[tmp] = true; } else{ for(int j = 1;j<k;j++){ if(tmp == set[j][0]){ if(peo[i].relation == 0) set[j][1]++; else set[j][2]++; break; } } } } for(int i = 0;i<=p;i++){ for(int j = 0;j<k;j++){ f[i][j] = 0; } } f[0][0] = 1; for(int i = 1;i<=p;i++){ for(int j = 1;j<k;j++){ if(i<set[j][1]&&i>=set[j][2]) f[i][j] = f[i-set[j][2]][j-1]; if(i>=set[j][1]&&i<set[j][2]) f[i][j] = f[i-set[j][1]][j-1]; if(i>=set[j][1]&&i>=set[j][2]) f[i][j] = f[i-set[j][1]][j-1]+f[i-set[j][2]][j-1]; if(f[i][j]>1) f[i][j] = 2; } } if(f[p][k-1]==1){ int num = p; for(int i = k-1;i>=1;i--){ if(num>=set[i][1]&&f[num-set[i][1]][i-1] == 1){ set[i][3] = 0; num = num -set[i][1]; } else if(num>=set[i][2]&&f[num - set[i][2]][i-1]==1){ set[i][3] = 1; num = num - set[i][2]; } } for(int i = 1;i<=p+q;i++){ int tmp = find(i); for(int j = 1;j<k;j++){ if(tmp == set[j][0]){ if(peo[i].relation == set[j][3]) cout<<i<<endl; break; } } } cout<<"end"<<endl; } else cout<<"no"<<endl; } return 0; }