浅谈并查集
前置芝士
并查集主要用于解决一些元素分组问题,有以下两种操作:
-
合并:把两个不相交的集合合并为一个集合。
-
查询:查询两个元素是否在同一个集合中。
一篇个人认为比较好的珂以推荐的并查集引入文章Link
举的栗子很生动;
开始码
普通并查集
我们跟着上面提到的文章的思路开始码:
void init(int n) {
//用作初始化
int i;
for (i = 1; i <= n; i++) {
node[i] = i;
}
}
由于我们一开始就给每个节点的值赋成了该节点的标号,
所以查询的时候只需要查编号是否相等即可;
int findgen(int i) {
//用于寻找根节点
if (node[i] == i) return i;
node[i] = findgen(node[i]);
}
如果珂以就合并;
但是还有一个问题需要考虑,
如果后面形成的不是我们所希望的一棵树的样子,而是直接成了一串,
会非常难找
这时候我们需要进行路径压缩,在过程中把沿途的每个节点的父节点都设为根节点
int findgen(int i) {
//用于寻找根节点
if (node[i] == i) return i;
node[i] = findgen(node[i]);
return node[i];
//return 0;
}
光这一点显然远远不够,我们需要来考虑合并的顺序,于是,有了下方的优化:
void hebing(int x, int y) {
//用于合并两棵树
x = findgen(x);//第1棵树的高度
y = findgen(y);//第2棵树的高度
if (x == y) return;
if (high[x] > high[y]) {
//如果第1棵树的高度高过第2棵树的高度
node[y] = x;
}
else if (high[x] == high[y]) {
node[y] = x;
high[x]++;
}
else node[x] = y;
return;
}
然而并查集的应用还有很多
留一道题目吧P3958
总之涉及到元素分组的问题可以直接并查集
种类并查集
一般的并查集,我们只需要维护连通性和传递性(如:亲戚的亲戚也是亲戚)这类的,
但是我们会遇到例如敌人的敌人是朋友这种关系,种类并查集是用来做这个的;
这里我们介绍一下方法:
我们先来开 1 个2倍大小的并查集,比如我们这道题上面,我们维护的是一个监狱里的人
那么,比如有 4 个人,因此考虑开 8 个单位空间,
(所有过程请见上图)
为了更加直观的表达这一关系,我们把两个敌人的编号分别设为 和
那么,我们就要 连接(i,j+n)
还有 连接(j,i+n)
本文作者:zsdqwq
本文链接:https://www.cnblogs.com/wo-de-bo-ke-wo-zuo-zhu/p/15844503.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步