并查集的定义和实现思路
并查集是一种维护集合类型的数据结构,它的名字中“并”“查”“集”分别取自union(合并)、find(查找)、set(集合)这三个单词。也就是说并查集支持下面的操作:
- 合并:对两个集合进行合并。
- 查找:判断两个元素是否为在一个集合。
具体实现:用数组father[N]来实现
其中father[i]表示元素i的父亲结点,父亲结点本身也是这个集合内的元素(1<=i<=N)。但是对于同一个集合来说只存在一个根结点,而且将其作为所诉集合的标识。
例如:
father[1]=1;//1的父亲就是自己,也就是说1是根节点
father[2]=1;//2的父亲结点是1
father[3]=1;//3的父亲结点是1
father[4]=1;//4的父亲结点是1
father[5]=4;//5的父亲结点是4
father[6]=4;//6的父亲结点是4
上述情况元素1-6都在同一个及格
2.并查集的基本操作
- 初始化
在一开始每一个元素都是独立的一个集合,因此要令所有的father[N]等于i。
for(int i=1;i<=n;i++){
//初始化不能忘记,注意让i=1
father[i]=i;
}
- 查找
反复寻找父亲结点直至找到根节点
int find(int x){
if(x==father[x]) return x;//直接找到了根节点
} else {
int t=find(father[x]);//递归找到father[x]的根节点
father[x]=t;//找到自己的父亲结点
return t;
}
- 合并
合并一般是给出两个元素,把这两个元素所在集合合并(若给出多个元素要有所处理)
int ufs(int a,int b){
int t1=find(a);
int t2=find(b);
if(t1!=t2){
father[t1]=t2;
}
}
注意如果一行给出多个元素需要读入,一般拿出来第一个元素出循环进行读入
直接给出代码:
for(int j=1;j<=m;j++){
cin>>a;
for(int i=1;i<=n-1;i++){
cin>>b;
ufs(a,b);//以两个两个一合并来遍历每一行
}
}
3.并查集的实例
输入样例:
7 4
3 1 2 3
2 1 4
3 5 6 7
1 6
输出样例:
4
这是一道并查集运用的题目,我们按照前文所讲给出代码:
#include<bits/stdc++.h>
using namespace std;
int num[30005];
int cn[30005];
int find(int x){
//查找模块
if(num[x]==x) return x;
else {
int t=find(num[x]);
num[x]=t;
return t;
}
}
void ufs(int e,int f){
//合并模块
int t1=find(e);
int t2=find(f);
if(t1!=t2) num[t1]=t2;
}
int main(){
int m,n;
cin>>m>>n;
for(int i=1;i<=m;i++) num[i]=i;
int a,b,c,d;
while(n--){
cin>>a;
cin>>b;
for(int i=1;i<=a-1;i++){
cin>>c;
ufs(b,c);
}
}
for(int i=1;i<=m;i++){
//对集合个数进行技术
cn[find(i)]++;
}
int max=0;//找出最大值
for(int i=1;i<=m;i++){
if(cn[i]>max) max=cn[i];
}
cout<<max<<endl;
return 0;
}
总结:并查集这种算法很常见,读者可以将并 查两个模板进行理解记忆,对后面的处理多多写题就可以理解,常见的基础类型就是并集集合个数、并集集合元素等等问题,一定要自己亲自敲几遍代码就可以理解。