种类并查集;

第一章、种类并查集

在这里插入图片描述
这是种类并查集的小图片,与并查集所不一样的是他的数组;和所需函数不同;应为对于种类之间的关系是不相同的。如上图所示
链接:例题:食物链:
这就是典型的种类并查集,加油思考!!!;
这道题也很难,搞不清楚状况,

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
int	n,k,t,x,y;
int ans=0;
int f[N];
int find(int n){//找祖先; 
	if(f[n]==n) return n;
	return f[n]=find(f[n]);
}
void merge(int x,int y){//判断同类; 
	int fx=find(x);
	int fy=find(y);
	if(fx!=fy) f[fx]=fy;
}
int main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++) f[i]=i;
	while(k--){
		cin>>t>>x>>y;
		if(t==1) merge(x,y);
		if(x>n||y>n){
			ans++;
			continue;
		}
		if(x==y&&t==2){
			ans++;
			continue;
		}
		if(find(x)==find(y)&&t==2){
			ans++;
			continue;
		}
	}
	cout<<ans;
	return 0;
}

这是一开始写出来的,仅仅只是简单的判断,但也有20分;接下来看ACcode:

#include<bits/stdc++.h>
using namespace std;
const int N=50005;//就是10^4+7;这是由n的数据范围规定的; 

int n,k,x,y,ch;//n是个数,k是说话的个数,xy是两个动物的编号 ch执行的关系;
int ans,f[3*N];;//假话的数量 //有三种关系;  

inline int find(int x){
	if(f[x]==x) return x;//假如说,n的朋友或敌人是自己,就是return自己;
	return f[x]=find(f[x]);//这是路径优化;也等同:
	/*f[n]=find(f[x]);
	return f[x];*/ 
}

inline bool check(int x,int y){//判断祖先的关系 
	int f1=find(x);
	int f2=find(y);
	if(f1==f2) return true;//如果x和y的朋友或敌人是同一人,就return true; 
	return false;//否则return false; 
}

inline void merge(int x,int y){
	int fx=find(x);
	int fy=find(y);
	if(fx==fy) return;//如果两个值相等,那么就是假话,不需要合并;
	if(fx<fy) f[fy]=fx;
	else f[fx]=fy;//保证单项合并(小的向大的靠拢) 
} 

int main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n>>k;//简单输入 
	for(int i=1;i<=3*n;i++) f[i]=i;//初始值要附上,n<<1是2*n的意思; 
	while(k--){
		cin>>ch>>x>>y;
		if(x>n||y>n){
			ans++;
			continue;//如果说已经是假话了,之后就不用再判断了; 
		}
		if(x==y){//当前的话中 x吃x就是假话;
			if(ch==2) ans++;
			continue;
		}
		if(ch==1){//一类型中 、朋友关系 
			if(check(x+n,y)||check(x,y+n)){
			    ans++;
				continue;
			}
			merge(x,y);
			merge(x+n,y+n);
			merge(x+(n<<1),y+(n<<1));//合并三个类型; 
		}
		if(ch==2){//二类型中 、敌对关系 
			if(check(x,y)||check(x+n,y)){//但又存在朋友关系 
				ans++;
				continue;
			}
			merge(x,y+n);
			merge(x+n,y+(n<<1));
			merge(x+(n<<1),y);//依旧合并三个类型;
		} 
	}
	cout<<ans;
	return 0;
}

详解尽在代码中!!!

其实这也不是很难

不过是加了个

inline bool check(int x,int y){//判断祖先的关系 
	int f1=find(x);
	int f2=find(y);
	if(f1==f2) return true;//如果x和y的朋友或敌人是同一人,就return true; 
	return false;//否则return false; 
}

仅此而已,只是情况太多了;加油删除线格式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值