并查集是一个用来管理元素分组情况的数据结构,当你需要查询两个元素是否属于同一集合,那么并查集是一个很好的选择。而且由于最小生成树中的Kruskal算法也用到了并查集,所以学习一下还是很有帮助的。
并查集初始化
将每个点都赋值为它自身
void init(){
for(int i=0;i<N;i++)
par[i]=i;
}
查找元素所在集合
在此处使用了一个优化,当查找的点的父辈不是根节点时,将路径上的所有元素都连到根节点
int find(int a){
if(par[a]==a){
return a;
}else{
return par[a]=find(par[a]);
}
}
合并元素
在此处使用了另一个优化,及通过判断深度来合并,防止并查集退化
void unite(int x,int y){
x=find(x);
y=find(y);
if(x==y) return ;
if(rank[x]>=rank[y])
par[y]=x;
else
par[x]=y;
if(rank[x]==rank[y]) rank[x]++;
}
判断两个元素是否为同一集合
bool same(int a,int b){
return find(a)==find(b);
}
完整代码
#include<stdio.h>
#define MAX_N 100
int par[MAX_N],rank[MAX_N],N;
void init(){
for(int i=0;i<N;i++)
par[i]=i;
}
int find(int a){
if(par[a]==a){
return a;
}else{
return par[a]=find(par[a]);
}
}
void unite(int x,int y){
x=find(x);
y=find(y);
if(x==y) return ;
if(rank[x]>=rank[y])
par[y]=x;
else
par[x]=y;
if(rank[x]==rank[y]) rank[x]++;
}
bool same(int a,int b){
return find(a)==find(b);
}
int main(){
int a,b;
init();
scanf("%d",&N);
for(int i=0;i<N;i++){
scanf("%d%d",&a,&b);
unite(a,b);
}
return 0;
}