poj1703 犯罪集团 并査集

哎哎。。刚刚开始学习并査集不久,就遇到这样一个问题,相当头疼,于是就搜解题报告,后面发现有一个人的思路给人很明了的赶脚....于是...盗版了过来..

第一个代码是把rank存放敌友关系,我有点没理解find过程中的rank的转变,如果有知道的可以指点在下,

第二个代码就是加一个数组存放敌人,在这个过程中,根据 D a b 我们就把a,b互相存为敌人,合并过程中就合并对方的敌人,也就是敌人的敌人是自己的朋友,然后就转变成了并査集的基础,合并相同的集合....

/*#include <iostream> 
#include <cstdio>
using namespace std;
int rank[100010];
int parent[100010];
void make_set(int n){
	for(int i=0;i<n;i++){
		parent[i]=i;
		rank[i]=0;//0代表和父节点同类,1代表异类 
	} 
}
int find_set(int x){
	int t=parent[x];
	if(x!=parent[x]){
		parent[x]=find_set(t);
		rank[x]=(rank[t]+rank[x])%2;//回溯跟新 和父节点相同为0,不同为1 
	}
	return parent[x];
}
void union_set(int x,int y){
	int fx=find_set(x);
	int fy=find_set(y);
	if(fx==fy)
		return;
	parent[fx]=fy;
	rank[fx]=(rank[x]+rank[y]+1)%2;//根据x与其根,y与其根,x与y的关系,推导出fx与fy的关系 
}
int main(){
	int nCase;
	scanf("%d",&nCase);
	while(nCase-->0){
		int n,m,a,b;
		char c;
		scanf("%d%d",&n,&m);
		make_set(n);
		while(m-->0){
			getchar();
			scanf("%c%d%d",&c,&a,&b);
			if(c=='D'){
				union_set(a,b); 
			}else{
				int x=find_set(a);
				int y=find_set(b);
				if(x==y){
					if(rank[a]==rank[b]){
						printf("In the same gang.\n");
					}else 	printf("In different gangs.\n");
				}else{
					printf("Not sure yet.\n");
				}				
			}
		}
	}
	return 0;
}*/

#include<stdio.h>

int father[100005];//看看有没有必要加秩,按其合并,加了快le几十ms
int enemy[100005];//存放敌人
int rank[100005];
void init(int n)
{
	for(int i=1;i<=n;i++)//注意从1开始
	{
		father[i]=i;
		enemy[i]=0;
		rank[i]=0;
	}
}

int find(int x)
{
	if(x!=father[x])
		father[x]=find(father[x]);
	return father[x];
}

void Union(int x,int y)
{
	int fx=find(x);
	int fy=find(y);
	if(fx == fy)
		return ;
	if(rank[fx]>rank[fy])
	{
		father[fy]=fx;
	}
	else
	{
		father[fx]=fy;
		if(rank[fx] == rank[fy])
			rank[fy]++;
	}
	//father[fx]=fy;
}

int main()
{
	int T;
	int n,m;
	int a,b;
	char c;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		init(n);
	    getchar();
		while(m--)
		{
			scanf("%c%d%d",&c,&a,&b);
	        getchar();
			if(c == 'D')
			{
				if(enemy[a]==0 && enemy[b] == 0)//开始a,b都没有敌人不用合并,存放对方为敌人
				{
					enemy[a]=b;enemy[b]=a;
				}
				else if(enemy[a] == 0)//a没有存放敌人,现在存放敌人b,而b有敌人,那么敌人的敌人是朋友,就合并
				{
					enemy[a]=b;
					Union(a,enemy[b]);
				}
				else if(enemy[b] == 0)//同理
				{
					enemy[b]=a;
					Union(b,enemy[a]);
				}
				else//都存在敌人,就都合并一次
				{
					Union(a,enemy[b]);
					Union(b,enemy[a]);
				}
			}
			else 
			{
				if(find(a) == find(b))//首先a,b在一个集合
					printf("In the same gang.\n");
				else if(find(a)==find(enemy[b])||find(b)==find(enemy[a]))/
					printf("In different gangs.\n");
				else
					printf("Not sure yet.\n");
			}
		}
	}
	return 0;
}



你可能感兴趣的:(有一点点技巧的并査集)