并查集(基本代码+poj1182食物链)

--------------------------------挑战编程部分-----------------------------------

并查集:

常用于查询元素a和元素b是否属于同一组

合并元素a和元素b所在的组


基本代码:【摘自挑战程序】


int par[MAX_X];		//父亲
int rank[MAX_X]; 	//树的高度

//初始化 
void init(int n){
	for(int i=0;i<n;i++){
		par[i]=i;
		rank[i]=0; 
	} 
} 

//查询树的根
int find(int x){
	if(par[x]==x){
		return x;
	}
	else{
		return par[x]=find(par[x]);
	}
} 

//合并x和y所属的集合
void unite(int x,int y){
	x=find(x);
	y=find(y);
	if(x==y) return;
	
	if(rank[x]<rank[y]){
		par[x]=y;
	}else{
		par[y]=x;
		if(rank[x]==rank[y]) rank[x]++;
	}
	
} 

//判断是否属于同一个集合
bool same(int x,int y){
	return find(x)==find(y);
} 


POJ1182食物链

书中介绍的主要解决方法是:

(i-A表示i属于种类A)

对每只队伍创建3个元素,分别属于A,B,C类。以下标N相隔

种类1 :x和y同属于同一类,分别合并x-A,y-A     x-B,y-B         x-C,y-C,

种类2 :x吃y…………………分别合并x-A,y-B     x-B,y-C         x-C,y-A,

注意在合并之前要先判断是否满足会矛盾。

【种类1检查x-A和y-B或者x-A和y-C是否属于同一组】

【种类2检查x-A和y-A或者x-A和y-C是否同一组】


#include <cstdio>
#define MAXN 50001

int par[3*MAXN],rank[3*MAXN];

//上方基本代码 

//-----------------华丽丽模板分割线 
int main(){
	int n,k,tot=0;
	int type,x,X,y,Y;
	scanf("%d%d",&n,&k);	
	init(3*n);
	for(int i=0;i<k;i++){
		scanf("%d%d%d",&type,&X,&Y);
		x=X-1,y=Y-1;
		
		if(x<0||x>=n||y<0||y>=n){
			tot++;
			continue;
		}
		
		if(type==1){
			if(same(x,y+n)||same(x,y+2*n)){
				tot++;
			}
			else{
				unite(x,y);
				unite(x+n,y+n); 
				unite(x+2*n,y+2*n);				
			}
		}
		else{
			if(same(x,y)||same(x,y+2*n)){
				tot++;
			}else{
				unite(x,y+n);
				unite(x+n,y+2*n);
				unite(x+2*n,y);				
			}
		}
	}
		printf("%d\n",tot);	
	
	return 0;
} 






你可能感兴趣的:(并查集(基本代码+poj1182食物链))