算法题-并查集

274 阅读1分钟

前言

笔试中碰到了类似题目,一下子就反应过来要用并查集,但是忘了如何构造并查集了,记录下来随时复习。

概念

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

  • 合并(Union):把两个不相交的集合合并为一个集合。
  • 查询(Find):查询两个元素是否在同一个集合中。

举个例子:有N个人,每个人编号为1、2……N。给出两两亲戚关系,如[1, 3]代表一号和三号是亲戚,给出一组这样的亲戚关系,问共有多少个家族(家族中的人有亲戚关系)?

并查集

可以用一个人来代表一个家族,这个人可以是任意的。

初始化

先假设所有人都没有亲戚关系,所以每个人都代表一个家族。

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

查询

递归的去寻找家族的代表人。因此判断两个人是否是同一个家族,只需要判断代表人是否是同一个人。

int find(int i) {
    if(uf[i] == i) {
        return i;
    } else {
        return find(uf[i]);
    }
}

合并

找到ij家族的代表人,然后将i家族的代表人替换为j家族的代表人即可。

void merge(int i, int j) {
    uf[find(i)] = find(j);
}

优化

完成以上最简单的并查集的初始化以及查询、合并两个功能,就可以解决大部分并查集问题了。

还有一些优化措施,如路径压缩等,详见参考。

参考

并查集参考博客