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; //存储到根结点的距离
};
相关推荐
勇闯逆流河4 小时前
【数据结构】堆
c语言·数据结构·算法
pystraf4 小时前
LG P9844 [ICPC 2021 Nanjing R] Paimon Segment Tree Solution
数据结构·c++·算法·线段树·洛谷
飞川撸码5 小时前
【LeetCode 热题100】739:每日温度(详细解析)(Go语言版)
算法·leetcode·golang
yuhao__z5 小时前
代码随想录算法训练营第六十六天| 图论11—卡码网97. 小明逛公园,127. 骑士的攻击
算法
Echo``5 小时前
3:OpenCV—视频播放
图像处理·人工智能·opencv·算法·机器学习·视觉检测·音视频
Nobkins6 小时前
2021ICPC四川省赛个人补题ABDHKLM
开发语言·数据结构·c++·算法·图论
88号技师6 小时前
2025年6月一区SCI-不实野燕麦优化算法Animated Oat Optimization-附Matlab免费代码
开发语言·算法·matlab·优化算法
ysy16480672397 小时前
03算法学习_977、有序数组的平方
学习·算法
codists7 小时前
《算法导论(第4版)》阅读笔记:p83-p85
算法
Tiny番茄8 小时前
归一化函数 & 激活函数
人工智能·算法·机器学习