acwing算法基础之数据结构--并查集算法

目录

  • [1 基础知识](#1 基础知识)
  • [2 模板](#2 模板)
  • [3 工程化](#3 工程化)

1 基础知识

并查集支持O(1)时间复杂度实现:

  1. 将两个集合合并。
  2. 询问两个元素是否在一个集合中。

基本原理:每个集合用一颗树来表示。树根的编号就是整个集合的编号。每个结点存储它的父结点,p[x]表示x的父结点。

问题1:如何判断树根:p[x] == x

问题2:如何求x的集合编号:while (p[x] != x) x = p[x];。上述为朴素做法,可以通过路径压缩,进行优化。

cpp 复制代码
int find(int x) {
	if (p[x] != x) p[x] = find(p[x]);
	return p[x];
}

问题3:如何合并两个集合:px是x的集合编号,py是y的集合编号:p[px] = py

2 模板

cpp 复制代码
(1)朴素并查集:

    int p[N]; //存储每个点的祖宗节点

    // 返回x的祖宗节点
    int find(int x)
    {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }

    // 初始化,假定节点编号是1~n
    for (int i = 1; i <= n; i ++ ) p[i] = i;

    // 合并a和b所在的两个集合:
    p[find(a)] = find(b);

(2)维护size的并查集:

    int p[N], size[N];
    //p[]存储每个点的祖宗节点, size[]只有祖宗节点的有意义,表示祖宗节点所在集合中的点的数量

    // 返回x的祖宗节点
    int find(int x)
    {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }

    // 初始化,假定节点编号是1~n
    for (int i = 1; i <= n; i ++ )
    {
        p[i] = i;
        size[i] = 1;
    }

    // 合并a和b所在的两个集合:
    size[find(b)] += size[find(a)];
    p[find(a)] = find(b);

(3)维护到祖宗节点距离的并查集:

    int p[N], d[N];
    //p[]存储每个点的祖宗节点, d[x]存储x到p[x]的距离

    // 返回x的祖宗节点
    int find(int x)
    {
        if (p[x] != x)
        {
            int u = find(p[x]);
            d[x] += d[p[x]];
            p[x] = u;
        }
        return p[x];
    }

    // 初始化,假定节点编号是1~n
    for (int i = 1; i <= n; i ++ )
    {
        p[i] = i;
        d[i] = 0;
    }

    // 合并a和b所在的两个集合:
    p[find(a)] = find(b);
    d[find(a)] = distance; // 根据具体问题,初始化find(a)的偏移量

3 工程化

cpp 复制代码
class UnionFind {
public:
	UnionFind(int n) {
		this->n = n;
		p.resize(n);
		cnt.resize(n);
		d.resize(n);
		for (int i = 0; i < n; ++i) {
			p[i] = i;
			cnt[i] = 1;
			d[i] = 0;
		}
	}

	int find(int x) {
		if (x != p[x]) {
			int u = find(p[x]);
			d[x] += d[p[x]];
			p[x] = u;
		}
		return p[x];
	}

	void merge(int x, int y) {
		int px = find(x), py = find(y);
		if (px != py) {
			p[px] = py;
			cnt[py] += cnt[px];		
		}
		return;
	}
	
	int size(int x) {//返回x所在集合的大小
	    return cnt[find(x)];
	}
private:
	int n;
	vector<int> p; //存储父结点
	vector<int> cnt; //存储集合大小,根结点的cnt才有意义
	vector<int> d; //存储到根结点的距离
};
相关推荐
hope_wisdom3 分钟前
C/C++数据结构之队列基础
c语言·数据结构·c++·队列·queue
不一样的故事1267 分钟前
高速采集箱
算法·信号处理
会员果汁35 分钟前
算法-拓扑排序-C
c语言·开发语言·算法
YGGP1 小时前
【Golang】LeetCode 72. 编辑距离
算法·leetcode
YGGP1 小时前
【Golang】LeetCode 62. 不同路径
算法·leetcode
资生算法程序员_畅想家_剑魔1 小时前
算法-回溯-14
java·开发语言·算法
致Great1 小时前
大模型对齐核心技术:从第一性原理完整推导 PPO 算法!
人工智能·算法·大模型·agent·智能体
_w_z_j_1 小时前
二叉树的右视图(BFS或DFS)
算法·深度优先·宽度优先
cyyt1 小时前
深度学习周报(12.22~12.28)
人工智能·算法·机器学习
WBluuue1 小时前
Codeforces Global 31 Div1+2(ABCD)
c++·算法