poj 1182食物链 扩展域并查集

这题也可以用边带权并查集,但是我觉得扩展域并查集更好理解。

对于每个点x 有三个域 分别是 同类域,捕食域和天敌域

当x和y是同类时,显然x和y的三个域对应相同

当x吃y时,x的同类域和y的天敌域并起来,x的捕食域和y的同类域并起来,由题目知道x->y->z 之间成环 所以z是吃x的  所以x的天敌域要和y的捕食域并起来

在并之前判断是否为真话

如果x和y是同类 有两个冲突:

1.x的捕食域和y的同类域是一个集合(x吃y)

2.x的同类域和y的捕食域是一个集合(y吃x)

如果x吃y 也有两个冲突

1.x的同类域和y的同类域是一个集合(x和y是同类)

2.y的捕食域和x的同类域是一个集合(y吃x)

我们用 x,x+n,x+2*n分别代表x的同类域,捕食域和天敌域  具体实现看代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 200100;
int fa[N],n,k;
void init(){
	for(int i = 1; i <= 3*n; i++) fa[i]=i;
}
int get(int x){
	if(x==fa[x]) return x;
	return fa[x]=get(fa[x]);
}
 
int main(){
	scanf("%d%d",&n,&k);
	int ans = 0;
	init();
	for(int i = 1; i <= k; i++){
		int x,y,d;
		scanf("%d%d%d",&d,&x,&y);
		if((d==2&&x==y)||(x>n)||(y>n)){
			ans++;
			continue;
		}else{
			if(d==1){
				if(get(x)==get(y+n)||get(x+n)==get(y)){
					ans++;
					continue;
				}	
				fa[get(x)]=get(y),fa[get(x+n)]=get(y+n),fa[get(x+2*n)]=get(y+2*n);
			}else{
				if(get(x)==get(y)||get(y+n)==get(x)){
					ans++;
					continue;
				}
				fa[get(x+n)]=get(y),fa[get(x)]=get(y+2*n),fa[get(x+2*n)]=get(y+n);
			}
		}
		//printf("i=%d ans=%d\n",i,ans);
	}
	printf("%d\n",ans);
	return 0;
}
原创文章 85 获赞 103 访问量 2483

猜你喜欢

转载自blog.csdn.net/weixin_43824564/article/details/105875142