一、引入
思考下面题目(并查集板子题)
洛谷P1551
二、概念
并查集是⼀种⾮常精巧⽽实⽤的树形数据结构,他主要是处理⼀些
不相交集合的合并和查询
的问
题。不相交集合,顾名思义,就是两个集合的交集为空集的⼀些集合。⽐如
1
,
3
,
5
和
2
,
4
,
6
,他俩的交集为空集。就是不相交集合。像2
,
3
,
5
和
1
,
3
,
5
就不是不相交集合。
使⽤并查集时,⾸先会存在⼀组不相交的动态集合
S={S1, S2,
⋯
,Sk}
,⼀般都会使⽤⼀个整数表示
集合中的⼀个元素。
每个集合可能包含⼀个或多个元素,并选出集合中的某个元素作为代表。每个集合中具体包含了
哪些元素是不关⼼的,具体选择哪个元素作为代表⼀般也是不关⼼的。我们关⼼的是,对于给定的元素,可以很快的找到这个元素所在的集合(的代表),以及合并两个元素所在的集合,⽽且这些操作的时间复杂度都是常数级。
三、思路
并查集用树型结构实现
用双亲表示法:
int f[x]=y;x节点的父亲是y
合并两个集合(即两棵树):合并两棵树的根节点:先找到各自的根节点,把根节点设立父子关系即可
查询两个节点是否在同一个集合(树):找到两个节点的根节点,看根节点是否相同
如何找根节点?
i=4;//i是要找父亲的节点
while(f[i]!=i)//令根节点的f[x]=x;
{
i=f[i];
}
四、例题代码
#include <stdlib.h>
#include <stdio.h>
# include <string.h>
//洛谷P1551
int n,m,p;
int f[5005];
//非递归版
/*int find(int x)
{
while(f[x]!=x)
{
x=f[x];
}
return x;
}*/
//递归版
int find(int x)
{
if(f[x]==x)
{
return x;
}
else{
//return find(f[x]);//普通方法(未优化)
return f[x]=find(f[x]);//路径压缩(优化方法)
}
}
int main()
{
int x,y,px,py;
scanf("%d %d %d",&n,&m,&p);
//初始化f[i]=i
for(int i=1;i<=n;i++)
{
f[i]=i;
}
for(int i=1;i<=m;i++)
{
scanf("%d %d",&x,&y);
px=find(x);//px是x的父亲
py=find(y);
f[px]=py;
//f[py]=px;
}
for(int i=1;i<=p;i++)
{
scanf("%d %d",&x,&y);
px=find(x);
py=find(y);
if(px==py)
{
printf("Yes\n");
}
else{
printf("No\n");
}
}
return 0;
}
五、并查集用处
1.和其他算法结合
2.是其他算法的中间过程