并查集及其启发式合并

并查集
  并查集一般用于对动态连通性的判断,主要应用于判断两个元素是否在同一个 集合,两个点是否连通,变量名等同性以及间接好友的判断。同时并查集经常作为 其他模板的一部分实现某些功能。   
  并查集常用于的题型为判断某两个元素是否属于同一个集合,判断图是否连通 或是否有环,或配合其他算法如最小生成树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(){
	
} 

另外,启发式合并不只是并查集用, 还在其他数据结构和树上问题中出现.

猜你喜欢

转载自blog.csdn.net/qq_41750091/article/details/84440719