并查集初步

并查集是什么?

并查集是一种树形的存储结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。——百度百科

并查集的思想

将n个元素进行合并或查询该集合的根节点,来判断两个元素是否属于同一个集合。

代码实现

初始化

for(int i=1;i<=n;i++) father[i]=i; //最开始每个元素都是自己的父亲,下文father简称为fa

查询

inline int getfather(int x) { //查询祖先 
	if(fa[x]==x) return x; //如果自己就是自己的父亲,则该点就是这棵树的祖先 
	return getfather(fa[x]); //递归查找 
}

合并

inline void merge(int x,int y) { //合并并查集 
	if(getfather(x)!=getfather(y)) //如果两点不属于同一个并查集 
		fa[getfahter(x)]=getfather(y); //使x的祖先的父亲等于y的祖先,即合并两个并查集 
}

路径压缩

路径压缩其实就是在查询祖先的递归过程中,使当前到的点的父亲指向根节点,那么在之后的操作中,时间复杂度即可将为O(1)。

代码如下:

inline int getfather(int x)       
{
    if(x==fa[x]) return x; //如果节点x的父亲就是自己,则返回x
    return fa[x]=getfather(fa[x]); //让x的父亲等于它的祖先
}

//在对并查集进行路径压缩是可能会导致栈溢出,可以用非递归版本while语句来实现

//在写查询和合并操作的时候,getfather函数一定要在merge函数的上面,不然会编译错误...

并查集的应用

例题:家族(亲戚)  链接:点击打开链接

题目分析

从给出的亲戚关系中合并集合,再判断两个元素是否属于同一集合即可。

代码如下:

#include
using namespace std;

int n,m,p,fa[5020];
int x,y;

inline int getfather(int x) { //查询祖先,详细如上
	if(fa[x]==x) return x;
	return getfather(fa[x]); 
}

inline void merge(int x,int y) { //合并集合,详细如上
	if(getfather(x)!=getfather(y)) 
		fa[getfather(x)]=getfather(y); 
}

inline void init() {
	scanf("%d%d%d",&n,&m,&p);
	for(int i=1;i<=n;i++) fa[i]=i; //初始化
	for(int i=1;i<=m;i++) {
		scanf("%d%d",&x,&y);
		merge(x,y); //合并集合
	} 
} 

inline void work() {
	for(int i=1;i<=p;i++) {
		scanf("%d%d",&x,&y);
		if(getfather(x)==getfather(y)) cout<<"Yes"<

/*有兴趣的还可以去刷一下NOI2002银河英雄传说,luogu上就有这题,链接:点击打开链接*/

 

 

你可能感兴趣的:(并查集初步)