首页 > 其他分享 >并查集

并查集

时间:2023-02-10 12:45:42浏览次数:64  
标签:int 查集 find fa 集合 节点

并查集

大佬笔记如下:
通俗易懂
https://zhuanlan.zhihu.com/p/93647900

并查集是什么?

主要用于解决一些元素分组的问题。它管理一系列不相交的集合,并支持两种操作:

  • 合并:把两个不相交的集合合并为一个集合。
  • 查询:查询两个元素是否在同一个集合中。
    作用:
  • 实现集合的合并与查找
  • 并查集的结构:用树来存储一个集合,不过不是二叉树
  • 如果两个点有共同的根,她们就在一个集合里
  • 合并两个点所在集合只需要把一个点的根接到另一个点的根下面就行
    注意: 并查集虽然可以进行合并操作,但是却无法进行分割操作。

亲戚问题(并查集模板题)

把所有人划分到若干个不相交的集合中,每个集合里的人彼此是亲戚。为了判断两个人是否为亲戚,只需看它们是否属于同一个集合即可。因此,这里就可以考虑用并查集进行维护

#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define bug(x) cout<<#x<<"=="<<x<<endl;
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int inf = 0xc0c0c0c0;

const int N  = 2e4 + 10;
map<string, int> name;
int fa[N];
int n, m;

//查询(找祖宗)
int find(int x) {
	return fa[x] == x ? x : fa[x] = find(fa[x]);
}

//合并(认主归宗)
void merge(int x, int y) {
	fa[find(x)] = find(y);
}

int main() {
	ios;
	cin >> n >> m;

	for (int i = 1; i <= n; i++) {
		fa[i] = i; //初始化
		string s;
		cin >> s;
		name[s] = i;
	}

	for (int i = 1; i <= m; i++) {
		int op;
		string s1, s2;
		cin >> op >> s1 >> s2;

		if (op == 1) merge(name[s1], name[s2]);
		else {
			if (find(name[s1]) != find(name[s2])) cout << 0 << endl;
			else cout << 1 << endl;
		}
	}

	return 0;
}

最简单版本的并查集代码

(1)初始化

int fa[N];
void init(int n) {
	for (int i = 1; i <= n; i++) {
		fa[i] = i;
	}
}

假如有编号为\(1,2,3,...,n\)的\(n\)个元素,我们用一个数组fa[N]存储每个元素的父节点(因为每个元素有且只有一个父节点,所以这是可行的)。一开始,我们先将它们的父节点设为自己。
image
(2)查询

写法1:
int find(int x) {
	if (fa[x] == x) return x;
	else return find(fa[x]);
}

写法2:
int find(int x) {
	return  fa[x] == x ? x : fa[x] = find(fa[x]);
}

我们用递归的写法实现对代表元素的查询:一层一层访问父节点,直至根节点(根节点的标志就是父节点是本身)。要判断两个元素是否属于同一个集合,只需要看它们的根节点是否相同即可。沿着树向上走,来查询包含这个元素的树的根是谁。如果两个节点走到了同一个根,那么就可以知道它们属于同一组。
image

(3)合并

void merge(int x, int y) {
	fa[find(x)] = find(y);
}

合并操作也是很简单的,先找到两个集合的代表元素,然后将前者的父节点设为后者即可。当然也可以将后者的父节点设为前者。即如下图所示,从一组的根向另一组的根相连,这样两棵树就变成了一棵树,也就把两个组合并为一个组了。
image

路径压缩

最简单的并查集效率是比较低的。最坏情况下会形成一条长长的链,随着链越来越长,我们想要从底部找到根节点会变得越来越难。
怎么解决呢?使用路径压缩的方法。既然我们只关心一个元素对应的根节点,那我们希望每个元素到根节点的路径尽可能短,最好只需要一步。
其实很好实现。只要我们在查询的过程中,把沿途的每个节点的父节点都设为根节点即可。下一次再查询时,就可以省很多事。这用递归写法容易实现:
合并(路径压缩)

int find(int x) {
	if (x == fa[x])
		return x;
	else {
		fa[x] = find(fa[x]);	//父节点设为根节点
		return fa[x];			//返回父节点
	}
}

以上代码常常简写为一行:

int find(int x) {
	return x == fa[x] ? x : (fa[x] = find(fa[x]));
}

image

注意: 赋值运算符=的优先级没有三目运算符?:高,所以这里要加括号。
路径压缩优化后,并查集的时间复杂度已经比较低了,绝大多数不相交集合的合并查询问题都能够解决。然而,对于某些时间卡得很紧的题目,我们还可以进一步优化。

按秩合并

可能的误解:以为路径压缩优化后,并查集始终都是一个菊花图(只有两层的树的俗称)。但其实,由于路径压缩只在查询时进行,也只压缩一条路径,所以并查集最终的结构任然可能是比较复杂的。例如,现在有一颗较复杂的树需要与一个单元素的集合合并:
image
假如这时要\(merge(7,8)\),是选择把\(7\)的父节点设为\(8\)好,还是把\(8\)的父节点设为\(7\)好呢?
当然是后者。因为如果把\(7\)的父节点设为\(8\)会使树的深度(树中最长链的长度)加深,原来的树中每个元素到根节点的距离都变长了,之后我们寻找根节点的路径也就会相应变长。虽然我们有路径压缩,但路径压缩也是会消耗时间的。而把\(8\)的父节点设为\(7\), 则不会有这个问题,因为它没有影响到不相关的节点。
image
这启发我们:我们应该把简单的树往复杂的树上合并,而不是相反。因为这样合并后,到根节点距离变长的节点个数比较少。

标签:int,查集,find,fa,集合,节点
From: https://www.cnblogs.com/csai-H/p/17108523.html

相关文章

  • 【YBT2023寒假Day8 C】图论题(图论)(并查集)(线段树合并)
    图论题题目链接:YBT2023寒假Day8C题目大意给你一个无向图,然后你会一直操作直到无法操作,每次找出一个满足条件的三元组(a,b,c),满足a<b<c,a,b与a,c之间有边,b,c之间没......
  • 2021 年百度之星·程序设计大赛 - 初赛二 1003 魔怔(并查集,联通性,欧拉回路)
    problemsolution发现除了起点和终点,剩下所有点周围的边都会被恰经过偶数次,所以这些点初始连向了偶数条白边。考虑由白边连接形成的图,每个连通块中度数为奇数的点一定为偶数......
  • 【Baltic2003】【BZOJ1370】Gang团伙(并查集,拆点)
    problem给定n个人朋友的朋友是朋友,敌人的敌人是朋友朋友之间组成一个团伙,求团伙数solution将每个点x拆成两个:x和x+n(分别表示x的朋友和敌人)如果x和y是朋友,就将x和y合并如果x......
  • 并查集判断(DSU)二分图
    并查集(DSU)判断二分图题目链接二分图性质当且仅当图中不存在奇数环偶数环时可以扭成这样但奇数环则不可以从染色法的角度来考虑:假设一个二分图中左边标号为1......
  • 种类并查集 洛谷 P2024 食物链
    题目描述动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B,B吃C,C吃A。现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道......
  • 带权并查集 区间统计
    带权并查集区间统计例题:​​HDU ZjnuStadium​​(模板)​​HDU3038HowManyAnswersAreWrong​​与普通并查集不同是新增加一个属性:dist[a]:表示a到父亲节点的距离操......
  • 【bzoj4668】冷战 (并查集按秩合并+朴素LCA)
    题目描述1946年3月5日,英国前首相温斯顿·丘吉尔在美国富尔顿发表“铁幕演说”,正式拉开了冷战序幕。美国和苏联同为世界上的“超级大国”,为了争夺世界霸权,两国及其盟国......
  • POJ 1611--The Suspects【并查集水题】
    TheSuspectsSevereacuterespiratorysyndrome(SARS),anatypicalpneumoniaofunknownaetiology,wasrecognizedasaglobalthreatinmid-March2003.Tominim......
  • poj 1182 食物链(并查集)
    食物链TimeLimit: 1000MS MemoryLimit: 10000KTotalSubmissions: 33156 Accepted: 9626Description动物王国中有三类动物A,B,C,这三类动物的食物链构成......
  • 并查集
    并查集并查集基础定义并查集是一种树型的数据结构,主要用于处理一些不相交集合的合并及查询问题(即所谓的并、查)。一些常见的用途有连通子图、最小生成树的Kruskal算法和......