说明
近几天在自学并查集,并且看了一些博客觉得他们讲的听清楚的,很容易懂,都是生动教学,把队首
的那个下标比喻为掌门,我在这里就不比作掌门了,毕竟我和他们不一样。下面,开始说一下简单并
查集是个什么东西,以及类似题目求解。
并查集定义
并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集
合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。
这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,
若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运
行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,
只能用并查集来描述。
并查集思路
并查集就在于找到每一串的第一个元素的作比较,在这里我们就把每一叫做一个队伍,而站在队伍第
一个人就是队长,刚刚开始的时候就是在还不知道谁和谁是一队的,就可以每个人都是队长,然后再
确定关系,比如两个人确定关系,就找着两个人的队长如果队长是一样的,那就说明这俩个人是一个
队伍里面的人,就没必要再合并了,如果队长不一样就说明这俩个队伍应该是一个队伍,就将俩个队
伍合并为一个队伍就行,如此操作,最终有联系的成员都会在一个队伍里面。
简单例题及解法
题目:朋友圈
有n个人,编号1-n。
现在有一个舞会,在舞会上,大家会相互介绍自己的朋友。
即: 如果a认识b,b认识c。那么在舞会上,a就会通过b认识到c。
现在,给出m个关系
每个关系描述:
a b
表示 编号为a和编号为b的人是朋友关系。
样例输入:
5 3
1 2
2 3
4 5
样例输出:
2
解题:
希望读者结合本人上面写的并查集思路一起看。
首先假设这个队伍的每个人都是队长,我们设指向自己的人是队长,然后等着确定关系,当有俩个人
确定关系的时候我们就可以找他们的队长,队长不一样就可以合并,合并也很简单,即让第一个的队
长指向第二个人的队长,或者让第二个人的队长指向第一个人的队长,这样就变成了一个队长,也就
变成了一个队伍,当确定完之后,再找有多少队长,就是有多少朋友圈了。
#include<stdio.h>
int search(int a[],int people)
{
int memory=people;//记住进来的那个人的位置
while(a[people]!=people)//找队长
people=a[people];
a[memory]=people;
//直接让进来的那个人指向第一个人,压缩路径,就是不用跳那么多下到队长那里
return people;//返回队长的位置
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
int a[100010]={0};
int b,c,cnt=0;
int i,leader1,leader2;
for(i=1;i<=n;i++)a[i]=i;//假设全部都是一队一个人,指向自己的人就是队长,全部是队长
for(i=0;i<m;i++)
{
scanf("%d%d",&b,&c);//需要加到一个组的俩人
leader1=search(a,b);//寻找b的队长
leader2=search(a,c);//寻找c的队长
if(leader1!=leader2)//俩个队长不一样就要合并俩个队,让队长变成其中一个就行了
a[leader1]=leader2;//让其中一个队长指向另一个队长就合并了
}
for(i=1;i<=n;i++)//计算有多少队长就有多少队伍
if(a[i]==i)cnt++;//如果他指向自己他就是队长
printf("%d\n",cnt);
}
return 0;
}
并查集就到这,不懂的可以留言问我。