poj 1182 ,并查集拓展域+向量,谈谈个人理解和做法

原题:poj 1182

做这道题因为我认为 -2%3 = 1 ,debug了一个多钟,吨吨吨吨吨。。。

题意:emm题目是中文的

这道题相较于并查集入门题,多了一个集合之间的关系:一样,吃或者被吃,这个时候假如按照传统并查集做法,将全部动物通过并查集分成A,B,C三类将会十分难操作。并查集是快速提供一个集合的关系的做法,假如我们在集合内关系之间存放吃,一样或者被吃这三种关系呢。在做的时候只需要让父节点不一样的结合在一起,一样的话就查询关系是不是给出来的关系,不就好了。

可能做法还是有点抽象,我们来看“图”,注意,完整的关系有吃,一样,被吃三种,因此使用0表示一样,吃表示1,被吃表示2,可以结合“图”理解一哈为什么要这么设:

我的理解:(向量加法中,同类的话食性一样,所以同类是0,a吃b,b吃c,所以a被c吃,因此a被c吃是a吃b,b吃c叠加出来的,所以被吃所代表的数字需要是吃的两倍,让1表示吃,则2表示被吃)

好得差不多了,放代码

#include<cstdio>
#include<iostream>
using namespace std;
const int maxn=50005;
struct node{
	int fat,relat;// 0:a b same 1: a eat b 2: a eaten by b
}gg[maxn];
int N,K,res;
int trace(int num){ //   !!!
	if(gg[num].fat==num) return num;
	else {		
		int temp=gg[num].fat;
		gg[num].fat=trace(temp);
		gg[num].relat=(3+gg[num].relat+gg[temp].relat)%3;//一定要保证大于0啊
		return gg[num].fat;
	}
}
int main(){
	cin>>N>>K;
	for(int i=1;i<=N;i++){
		gg[i].fat=i;
		gg[i].relat=0;
	}
	res=0;
	while(K--){
		int flag,a,b;
		scanf("%d %d %d",&flag,&a,&b);
		if(a>N||b>N){
			res++; continue;
		}
		if(flag==2&&a==b){
			res++;
			continue;
		}
		int t_a=trace(a),t_b=trace(b);
		if(t_a!=t_b){
			gg[t_b].fat=t_a;
			gg[t_b].relat=(3+gg[a].relat-gg[b].relat-(flag-1))%3;
		}
		else{
			if((3+gg[a].relat-gg[b].relat)%3 != (flag-1)){
				res++;
			} 
		}
	}
	cout<<res;
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/weixin_43191865/article/details/88566233