并查集(擒贼先擒王)

引入

  • 并查集也被称为不相交集数据结构
  • 我们来从一个例题说起

有若干个强盗 有若干个线索,每个线索中的两个强盗为同伙(倘若A与B是同伙,B与C是同伙,那么A与C也是同伙),判断有多少个独立的犯罪团伙。
样例数据:
10 9 //10个强盗 9条线索
1 2
3 4
5 2
4 6
2 6
8 7
9 7
1 6
2 4

分析

1.我们可以先确定一个数组,把每个强盗的首领存放在数组里,序号代表第几个强盗,里面存储的数据则代表强盗的首领,先把每个强盗的首领当作是自己
2.然后从线索的第一条进行查找,1 2,就是1号和2号的首领是一个人,我们做一个规定,左边的人权力更大,则2号顶点的首领是1号顶点,改变f[2]的值,f[2]=1
3.第二条线索,3 4,根据规定f[4]=3
4.第三条线索,5 2,根据规定f[2]=5,但是2号强盗本来是1号强盗的人,1号强盗就不愿意了,为什么要抢我的人呢?我们就检测f[2]的boss是不是它自己,如果不是,就让5号与2号强盗的首领谈,让她归顺自己,即f[f[2]]=5,就是f[1]=5,同时现在5号是最大的boss,寻找2号的最大boss时,改变f[2]的值让f[2]=5
5.第四条线索,4 6,根据规定,因为4号强盗的boss不是自己,所以要让f[6]=3
6.第五条线索,2 6,f[2]=5,f[6]=3,根据规定f[3]=5
7.第六条线索,7 11,根据规定f[11]=7
8.第七条线索,8 7,根据规定f[7]=8
9.第八条线索,9 7,根据规则f[8]=9
10.第九条线索,9 11,我们发现9号和11号的首领不是同一个人,因为f[9]=9,f[11]=7,好像不在同一个集团,但是不对吧,根据递归f[11]=7,f[7]=8,f[8]=9,明明是一个,我们就要找到各自的最大首领来判断,要不然就会出现错误

代码实现

#include<stdio.h>
int n,m,sum=0,f[1001]={0};
//初始化数组 
void init(){
	int i;
	for(i=1;i<=n;i++)
		f[i]=i;
	return;
}
//找爹的递归函数,不停的去找爹
//直到找到祖宗为止,其实就是去找犯罪团伙的最高领导人 
//擒贼先擒王原则 
int getf(int v){
	if(f[v]==v)
		return v;
	else{
		//这里是路径压缩,每次在函数返回的时候,顺带把路上遇到的人的"BOSS"
		//改为最后找到的祖宗编号,也就是犯罪团伙的最高领导人编号 
		f[v]=getf(f[v]);//这里进行了路径压缩 
		return f[v];
	}
}
//合并两子集的函数 
void merge(int v,int u){
	int t1,t2;//t1、t2分别为v和u的大BOSS 
	t1=getf(v);
	t2=getf(u);
	if(t1!=t2)//判断两个结点是否在同一个集合中,即是否为同一个祖先 
		//靠左原则,左边变成右边的BOSS 
		f[t2]=t1;
	return;
}
int main(){
	int i,x,y;
	scanf("%d %d",&n,&m);
	//初始化 
	init();
	for(i=1;i<=m;i++){
		//开始合并犯罪团伙 
		scanf("%d %d",&x,&y);
		merge(x,y);
	}
	//最后扫描有多少个独立的犯罪团伙 
	for(i=1;i<=n;i++){
		if(f[i]==i)
			sum++;
	}
	printf("%d",sum);
	return 0;
}
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值