首页 > 其他分享 >数据结构:并查集 学习笔记

数据结构:并查集 学习笔记

时间:2022-12-28 13:56:12浏览次数:71  
标签:get int 查集 笔记 查询 集合 数据结构 节点

数据结构:并查集 学习笔记

基础知识

并查集是一种树形数据结构。在全国青少年信息学奥林匹克系列竞赛大纲中难度为 6,是提高级中学习的数据结构。

并查集的基本操作:

  1. 查询一个元素在哪个集合。
  2. 合并两个集合。

使用一个森林来存储并查集,一个元素是一个结点,每棵树是一个集合。用一个数组 f 来记录父亲表示法。即 f[x] 表示元素节点 x 的父亲。这样,查询一个元素在哪个集合就是查询节点所在树的根节点,合并两个集合,就是把一颗树的根节点的父亲设置成另外一棵树的根节点。

并查集的优化

并查集有两种常用的优化操作,一种优化查询,一种优化合并。

查询:使用路径压缩,比较常用。容易发现,并查集只需要元素所在树的根节点,树的形态对操作没有影响。所以,可以在查询的时候,把所有查询的节点的父亲直接改成树根。(图来自《算法竞赛进阶指南》)
img

合并:使用启发式合并。把节点少的树合并到节点多的树上,一般只在边带权并查集中使用。这里不过多介绍,请读者自行查询相关资料。

并查集的代码实现

洛谷 P3367 【模板】并查集

题目链接
并查集模板,要注意初始化,即每个元素所在的集合最开始只有自身。

#include <iostream>
using namespace std;

// 1. 并查集的存储
int f[100005], n; // 并查集中有 n 个元素

// 2. 并查集的查询(带路径压缩优化)
int get(int x)
{
    if (f[x] == x)
        return x; // x 是根节点
    return f[x] = get(f[x]); // 递归寻找根节点,并且进行路径压缩
}

// 3. 并查集的合并
void merge(int x, int y)
{
    f[get(x)] = get(y);
}

int main()
{
    int m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        f[i] = i; // 4. 并查集的初始化
    while (m--) {
        int x, y, z;
        cin >> z >> x >> y;
        if (z == 1)
            merge(x, y);
        else {
            if (get(x) == get(y))
                cout << 'Y' << endl;
            else
                cout << 'N' << endl;
        }
    }
    return 0;
}

统计并查集集合个数

在一些题中,需要我们统计并查集中集合个数。统计有多少树的根节点即可(根节点的父节点是他本身)
我们来看下面这题:

洛谷 P1536 村村通

题目链接

题目描述:
某市调查城镇交通状况,得到现有城镇道路统计表。表中列出了每条道路直接连通的城镇。市政府 "村村通工程" 的目标是使全市任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要相互之间可达即可)。请你计算出最少还需要建设多少条道路?

输入格式:
输入包含若干组测试数据,每组测试数据的第一行给出两个用空格隔开的正整数,分别是城镇数目 n 和道路数目 m ;随后的 m 行对应 m 条道路,每行给出一对用空格隔开的正整数,分别是该条道路直接相连的两个城镇的编号。简单起见,城镇从 1 到 n 编号。注意:两个城市间可以有多条道路相通。在输入数据的最后,为一行一个整数 0,代表测试数据的结尾。

输出格式:
对于每组数据,对应一行一个整数。表示最少还需要建设的道路数目。

做法:
初始时,我们用并查集把所有直接连通的城镇合并。统计出集合数,显然集合数减一就是最少要建设的道路。

参考代码:

#include <iostream>
using namespace std;

int f[1005], n, m;
int get(int x)
{
    // 1. 并查集的查询,这里我用三元表达式压了下行
    return (f[x] == x) ? (x) : (f[x] = get(f[x]));
}

int main()
{
    ios::sync_with_stdio(0);
    do {
        cin >> n;
        if (n == 0)
            break;
        cin >> m;
        for (int i = 1; i <= n; i++)
            f[i] = i;
        for (int i = 1; i <= m; i++) {
            int x, y;
            cin >> x >> y;
            f[get(x)] = get(y); // 2. 并查集的合并
        }
        int ans = 0;
        for (int i = 1; i <= n; i++)
            ans += (i == get(i)); // 3. 统计集合个数(就是统计根节点个数)
        cout << ans - 1 << endl;
    } while (n != 0);
    return 0;
}

带权并查集

有时候,我们除了需要并查集的两个基本操作外,还需要维护节点或者集合的一些其他信息。当我们维护集合的信息时,可以把信息记在集合的根节点上。当我们维护节点的信息是节点到根节点的距离或者其他与根节点相关的信息时,就使用边带权并查集,把信息记在节点到父节点的边上,在路径压缩时处理。

洛谷 P1196 [NOI2002] 银河英雄传说

(未完待续)

标签:get,int,查集,笔记,查询,集合,数据结构,节点
From: https://www.cnblogs.com/JXOIer-zaochen/p/16997939.html

相关文章

  • 手机上的机器学习资源!Github标星过万的吴恩达机器学习、深度学习课程笔记,《统计学习方
    吴恩达机器学习、深度学习,李航老师《统计学习方法》、CS229数学基础等,可以说是机器学习入门的宝典。本文推荐一个网站“机器学习初学者”,把以上资源的笔记、代码实现做成了......
  • 数据结构学习笔记 (参考书籍:《大话数据结构》)
    数据结构线性表顺序存储优点:无须为表中元素之间的逻辑关系而增加额外的存储空间;可以快速的存取表中任一位置的元素。缺点:插入和删除操作需要移动大量元素;当线性表长度......
  • 关于HTML元素高度属性+滚动到底部实现的笔记
    clientHeight元素像素的可视高度,包含元素的高度+内边距,不包含水平滚动条,边框和外边距 offsetHeight元素像素的可视高度,包含元素的垂直内边距和边框,水平滚动条的高度,且......
  • .NET 云原生架构师训练营(基于 OP Storming 和 Actor 的大型分布式架构一)--学习笔记
    目录为什么我们用OrleansDaprVSOrleansActor模型Orleans的核心概念为什么我们用Orleans分布式系统开发、测试的难度(服务发现、通信)运维的复杂度(伸缩性与可靠性的保障)a......
  • 分治学习笔记
    算法思想分治的主要思想就是分而治之,即把一个大问题分成若干个小问题,先去解决这些小问题,再去解决大问题。分治是一个思想,我们通过一些实际应用来感受一下。归并排序归......
  • LCA 学习笔记
    概念LCALCA(LowestCommonAncestor),即最近公共祖先,指的是一棵树中任意两个节点深度最大的共同祖先。有啥用树有一个性质,两点之间有且只有一条简单路径,如果我们把1......
  • ST表学习笔记
    RMQ问题RMQ(RangeMinimum/MaximumQuery)问题是指多次查询某个范围内的最大最小值(或极值),比如对一个序列多次查询区间的最大最小值。设范围内共有\(n\)个元素,查询\(m\)......
  • 最小生成树学习笔记
    基本概念树定义:树是一个连通且无环的简单无向图。一个\(n\)树有以下三个特点:联通。无环。\(n-1\)条边。上面任意两个条件满足都可以得出这个图是一个......
  • Spring学习笔记 - 第三章 - AOP与Spring事务
    原文地址:Spring学习笔记-第三章-AOP与Spring事务Spring学习笔记全系列传送门:Spring学习笔记-第一章-IoC(控制反转)、IoC容器、Bean的实例化与生命周期、DI(依......
  • SSM框架视频笔记
    Date:2022-12-2800:35:29【尚硅谷】SSM框架全套教程,MyBatis+Spring+SpringMVC+SSM整合一套通关半夜学习的我像个小丑......