poj1703

并查集水题。循环路径并查集

关键是合并关联集合,分析如下:现有关系A a,b(a与b属于不同集合)

那么现在要做的就是将a关联集合与b关联集合和并,问题:如何合并?

必定是对父节点合并,那么转换关系如何?

分析如下:

路径压缩后,令deep[a]表示a的深度,其根节点为x,令deep[b]表示b的深度,其根节点为y,那么若将x集合与y集合合并(假设合并后根节点为x),则合并后b的深度应该为:

deep[b]=(deep[a]+1)%2;而此时deep[b]=deep[y]+deep[b],故有deep[y]+deep[b]=(deep[a]+1)%2;也即deep[y]=(deep[a]+1-deep[b])%2,这样就将x集合和y集合合并在一起了,这是核心,接下来主函数就只需要判断深度关系即可判断对应的关系。典型的循环路径压缩并查集。

下面是代码:940K+360MS

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Max 100010
#define Maxx(a,b) (a)>(b)?(a):(b)
#define Min(a,b) (a)<(b)?(a):(b)
int set[Max];
int deep[Max];
int c,n,m;
int find(int x){
	if(x==set[x])
		return x;
	int temp=find(set[x]); // 递归寻找根节点
	deep[x]=(deep[x]+deep[set[x]])%2; //更新深度
	set[x]=temp; //路径压缩
	return temp; //返回根节点
}
int main(){
	scanf("%d",&c);
	while(c--){
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++){ //初始化深度为0
			set[i]=i;
			deep[i]=0;
		}
		int a,b,x,y;
		while(m--){
			getchar();
			char temp=getchar();
			if(temp=='A'){ //若为A,则检查关系
				scanf("%d%d",&a,&b);
				x=find(a),y=find(b);
				if(x!=y) //若还没有产生关系
					printf("Not sure yet.\n");
				else{ //否则必定存在关系
					if(deep[a]!=deep[b]) // 若深度相同,则说明是同类
						printf("In different gangs.\n");
					else //否则不是同类
						printf("In the same gang.\n");
				}
			}
			else{
				scanf("%d%d",&a,&b);
				x=find(a),y=find(b); //查找根节点
				if(x<y){ //大并小
					deep[y]=(deep[a]+1-deep[b])%2; //路径更新
					set[y]=x;
				}
				else if(y<x){ 
					deep[x]=(deep[b]+1-deep[a])%2;
					set[x]=y;
				}
			}
		}
	}
	return 0;
}
					


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值