什么是并查集?
并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。集就是让每个元素构成一个单元素的集合,并就是按一定顺序将属于同一组的元素所在的集合合并。
并查集的主要操作:
1、初始化:把每个点所在集合初始化为其自身;
2、查找:查找元素所在的集合即根节点;
3、合并:将两个元素所在的集合合并为一个集合,合并两个不相交集合判断两个元素是否属于同一集合。
(1)初始化:
for(int i=0;i<n;i++)
father[i]=i;
因为每个元素属于单独的一个集合,所以每个元素以自己作为根结点。
(2)寻找根结点编号:
int find(int x)
{
while(father[x]!=x)
x=father[x];
return x;
}
(3)合并两个集合:
void merge(int a,int b)
{
int p=find(a);
int q=find(b);
if(p!=q)
father[p]=q;
}
(4)
判断元素是否属于同一集合:
function judge(x, y : integer) : boolean;
begin
x:=getfaher(x);
y:=getfather(y);
if x=y then exit(true)
else exit(false);
end;
下面看一个最基础的例子、
例题1、亲戚
【问题描述】
若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。
规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚。如果x,y是亲戚,那么x的亲戚都是y的亲戚,y的亲戚也都是x的亲戚。
【输入】
第一行:三个整数n,m,p,(n<=5000,m<=5000,p<=5000),分别表示有n个人,m个亲戚关系,询问p对亲戚关系。
以下m行:每行两个数Mi,Mj,1<=Mi,Mj<=N,表示Ai和Bi具有亲戚关系。
接下来p行:每行两个数Pi,Pj,询问Pi和Pj是否具有亲戚关系。
【输出】
P行,每行一个‘Yes’或‘No’。表示第i个询问的答案为“具有”或“不具有”亲戚关系。
【样例输入】
9 7 3
2 4
5 7
1 3
8 9
1 2
5 6
2 3
2 5
2 4
3 8
【样例输出】
No
Yes
No
(1)具体操作:
① 由此用某个元素所在树的根结点表示该元素所在的集合;
② 判断两个元素时候属于同一个集合的时候,只需要判断他们所在树的根结点是否一样即可;
③ 也就是说,当我们合并两个集合的时候,只需要在两个根结点之间连边即可。
(2)元素的合并图示:
(3)判断元素是否属于同一集合:
用father[i]表示元素i的父亲结点
faher[1]:=1;faher[2]:=1;faher[3]:=1;faher[4]:=5;faher[5]:=3。
参考程序:
#include<stdio.h>
int father[5010];
int find(int a)
{
while(father[a]!=a)
a=father[a];
return a;
}
void merge(int x,int y)
{
x=find(x);
y=find(y);
if(x!=y)
father[y]=x;
}
int main()
{
int i,j,m,n,p,zu1,zu2,sh1,sh2;
while(scanf("%d%d%d",&m,&n,&p)!=EOF)
{
for(i=0;i<n;i++)
father[i]=i;
for(i=0;i<n;i++)
{
scanf("%d%d",&zu1,&zu2);
merge(zu1,zu2);
}
for(i=0;i<p;i++)
{
scanf("%d%d",&sh1,&sh2);
sh1=find(sh1);
sh2=find(sh2);
if(sh1==sh2)
printf("Yes\n");
else
printf("No\n");
}
}
return 0;
}