并查集
并查集一般用于对动态连通性的判断,主要应用于判断两个元素是否在同一个 集合,两个点是否连通,变量名等同性以及间接好友的判断。同时并查集经常作为 其他模板的一部分实现某些功能。
并查集常用于的题型为判断某两个元素是否属于同一个集合,判断图是否连通 或是否有环,或配合其他算法如最小生成树Kruskal,与DP共同使用等。(摘自大神)
直接看代码注释解释
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int fa[maxn];
void init(int n){//初始化,每个节点以自己为父节点
for(int i=1;i<=n;i++) fa[i]=i;
}
int find(int u){//找父亲节点,采用递归方法
if(fa[u]==u) return u;//相同就返回
else {//不同递归找父节点
fa[u]=find(fa[u]);
return fa[u];
}
}
void merge(int u,int v){//u->v 将u并到v中
int t1=find(u),t2=find(v);
if(t1!=t2){//如果不同就合并
f[t1]=t2;
}
}
int main(){
}
因为本人强迫症,老喜欢节省代码量,所以节省为如下代码。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int fa[maxn];
void init(int n){
for(int i=1;i<=n;i++) fa[i]=i;
}
int find(int u){
return fa[u]==u?fa[u]:fa[u]=find(fa[u]);
}
void merge(int u,int v){
fa[find(v)]=find(u);
}
int main(){
}
接下来讲启发式合并是对并查集优化。
优化的理论是用一个数组来记录每个节点的深度,每一次合并都把节点向深度(高度)大的节点上进行合并,从而对最后的“生成树”深度进行了优化。
下面是代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int fa[maxn];
int rank[maxn];//记录节点深度。
void init(int n){
for(int i=1;i<=n;i++) fa[i]=i;
}
int find(int u){
return fa[u]==u?fa[u]:fa[u]=find(fa[u]);
}
void merge(int u,int v){
int t1=find(u);
int t2=find(v);
if(t1!=t2) {//启发式算法的核心代码,将节点深度小的并到节点深度大的上面。
if(rank[t1]>rank[t2]){
f[t2]=t1;
}
else if(rank[t1]<rank[t2]){
f[t1]=t2;
}
else {
f[t2]=t1;
rank[t1]++;
}
}
}
int main(){
}
另外,启发式合并不只是并查集用, 还在其他数据结构和树上问题中出现.