poj1417DP+并查集

解题思路 :当是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;	
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值