“天意终究难参,假若登顶成憾,与君|

zsdqwq

园龄:3年6个月粉丝:9关注:17

浅谈并查集

前置芝士

并查集主要用于解决一些元素分组问题,有以下两种操作:

  • 合并:把两个不相交的集合合并为一个集合。

  • 查询:查询两个元素是否在同一个集合中。

一篇个人认为比较好的珂以推荐的并查集引入文章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 个单位空间,

(所有过程请见上图)

为了更加直观的表达这一关系,我们把两个敌人的编号分别设为 ij

那么,我们就要 连接(i,j+n) 还有 连接(j,i+n)

本文作者:zsdqwq

本文链接:https://www.cnblogs.com/wo-de-bo-ke-wo-zuo-zhu/p/15844503.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   zsdqwq  阅读(49)  评论(0编辑  收藏  举报
评论
收藏
关注
推荐
深色
回顶
收起
点击右上角即可分享
微信分享提示