【算法基础:数据结构】2.3 并查集

news2024/11/25 18:32:31

文章目录

  • 并查集
    • 算法原理(重要!⭐)
  • 经典例题
    • 836. 合并集合(重要!模板!⭐)
    • 837. 连通块中点的数量(维护连通块大小的并查集)
    • 240. 食物链(维护额外信息的并查集)🚹🚹🚹
  • 相关链接
  • 相关题目

并查集

https://oi-wiki.org/ds/dsu/
在这里插入图片描述

操作:

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

(路径压缩优化之后):近乎 O ( 1 ) O(1) O(1)

算法原理(重要!⭐)

在这里插入图片描述

将每个集合使用树的形式存储。

每个集合的编号 是 树根的编号。

每个节点存储 它的父节点是谁。 p[x] 表示 x 的父节点。


Q:如何判断树根?
A:p[x] == x

Q:如何求 x 的集合编号?
A:while (p[x] != x) x = p[x];
使用 路径压缩 的话就是 if (p[x] != x) p[x] = find(x);

Q:如何合并两个集合?
A:p[x] = y,即 把一棵树的根节点当成另一个树根节点的儿子。 (优化!:将这棵树中的所有节点都当成另一棵树根节点的子节点——优化之后几乎就是 O ( 1 ) O(1) O(1) 的了)(这个优化叫做 路径压缩

经典例题

836. 合并集合(重要!模板!⭐)

https://www.acwing.com/activity/content/problem/content/885/
在这里插入图片描述

注意下面 find(x) 的写法。

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    static int[] p;
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(), m = scanner.nextInt();
        p = new int[n + 1];
        Arrays.setAll(p, e -> e);   // 初始化,各个节点的祖宗节点设置成自己
        while (m-- != 0) {
            char op = scanner.next().charAt(0);
            int a = scanner.nextInt(), b = scanner.nextInt();
            if (op == 'M') {
                p[find(a)] = find(b);
            } else {
                if (find(a) == find(b)) System.out.println("Yes");
                else System.out.println("No");
            }
        }
    }

    // 返回 x 的祖宗节点 + 路径压缩
    static int find(int x) {
        if (p[x] != x) p[x] = find(p[x]);	// 路径压缩
        return p[x];
    }
}

837. 连通块中点的数量(维护连通块大小的并查集)

https://www.acwing.com/activity/content/problem/content/886/

在这里插入图片描述

find(x) 方法没有变化。

在合并两个点时:
先检查两个点是否已经在同一个连通块里了,直接 continue;
否则,先将一个点的根节点维护的数量加到另一个点的根节点维护的数量,然后再合并这两个点。

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    static int[] p, size;       // p[i][0]是父节点  p[i][1]是该连通块中点的数量
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(), m = scanner.nextInt();
        p = new int[n + 1];
        size = new int[n + 1];
        Arrays.setAll(p, e ->e);   // 初始化,各个节点的祖宗节点设置成自己
        Arrays.fill(size, 1);   // 初始化每个连通块的大小是 1
        while (m-- != 0) {
            String op = scanner.next();
            int a = scanner.nextInt();
            if ("C".equals(op)) {
                int b = scanner.nextInt();
                if (find(a) == find(b)) continue;       // 已经在同一个连通块里了
                size[find(b)] += size[find(a)];
                p[find(a)] = find(b);
            } else if ("Q1".equals(op)) {
                int b = scanner.nextInt();
                if (find(a) == find(b)) System.out.println("Yes");
                else System.out.println("No");
            } else {
                System.out.println(size[find(a)]);
            }
        }
    }

    // 返回 x 的祖宗节点 + 路径压缩
    static int find(int x) {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }
}

240. 食物链(维护额外信息的并查集)🚹🚹🚹

https://www.acwing.com/activity/content/problem/content/887/
在这里插入图片描述

同一个集合表示:这一个集合内的所有动物之间的关系都可以确定。

对于每一句话中的 x 和 y,先检查它们是否在一个集合里,如果在同一个集合里,那么就可以判断这句话是否是假话。
如果是假话—— ++ans
如果是真话—— 将它们所在的两个集合合并。

如何确定同一个集合里各个动物之间的关系?
使用 d 数组维护各个节点到根节点之间的距离。(具体可以看下图:)

在这里插入图片描述
注意看代码中注释的解释。

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    static int[] p, d;
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt(), k = scanner.nextInt(), ans = 0;
        // 一个集合里的所有动物之间的关系是可以推理出来的(这里同一个连通块并不表示它们是同一个种类,而是它们之间的关系可以确定)
        // 记录每个点和根节点的关系(用每个点和根节点之间的距离来表示它和根节点之间的距离)
        p = new int[n + 1];
        Arrays.setAll(p, e ->e);    // 初始化,各个节点的祖宗节点设置成自己
        d = new int[n + 1];         // d 维护的是各个节点到根节点的距离(距离表示它和根节点之间的关系)

        while (k-- != 0) {
            int op = scanner.nextInt(), x = scanner.nextInt(), y = scanner.nextInt();
            if (x > n || y > n) {               // x 或 y 比 n 大 —— 是假话
                ++ans;
                continue;
            }

            int px = find(x), py = find(y);     // 找到 x 和 y 的祖宗节点
            if (op == 1) {
                if (px == py && (d[x] - d[y]) % 3 != 0) ++ans;  // 已经在一个集合里了,判断是否合理
                else if (px != py) {            // 不在一个集合里,确定关系
                    p[px] = p[py];
                    d[px] = d[y] - d[x];        // 是为了令 d[px] + d[x] == d[y]
                }
            } else {
                if (px == py && (d[x] - d[y] - 1) % 3 != 0) ans++;  // 已经在一个集合里了,判断是否合理
                else if (px != py) {
                    p[px] = py;
                    d[px] = d[y] - d[x] + 1;    // x 吃 y,是为了令d[px] + d[x] = d[y] + 1。
                }
            }
        }
        System.out.println(ans);
    }

    static int find(int x) {
        if (p[x] != x) {
            int t = find(p[x]);     // t 是 x 的父节点的父节点
            d[x] += d[p[x]];        // 在路径压缩的过程中,子节点需要继承父节点到根节点的距离。(因为没压缩之前 d[x]是x到p[x]之间的距离)
            p[x] = t;
        }
        return p[x];
    }
}

关于 d[px] 的确定:
在这里插入图片描述

相关链接

https://oi-wiki.org/ds/dsu/

相关题目

1851. 包含每个查询的最小区间

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/770494.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Spring | 应用上下文】

应用上下文 应用上下文和资源路径构造应用上下文构造ClassPathXmlApplicationContext实例 — 快捷方式使用通配符蚂蚁式图案类路径:前缀 应用上下文和资源路径 本节介绍如何使用资源创建应用程序上下文,包括使用 XML 的快捷方式、如何使用通配符以及其…

能耗管理平台保障用电的安全

安科瑞虞佳豪 壹捌柒陆壹伍玖玖零玖叁 6月12日,江苏盐城射阳县某民房起火,消防救援人员到场后,立即对火势进行扑救,经过20多分钟的处置,现场明火全部被扑灭,据了解,起火原因是电线老化短路引发…

Mac下makefile使用openssl库

程序报错 ./polipo.h:208:10: fatal error: openssl/ssl.h file not found 安装和查找openssl开发库 brew install brew --prefix openssl cd /opt/homebrew/opt/openssl3 cd lib cd pkgconfig 通过makefile配置include文件和lib文件 pkg-config方式 lib文件查找&#xf…

C# 同构字符串

205 同构字符串 给定两个字符串 s 和 t ,判断它们是否是同构的。 如果 s 中的字符可以按某种映射关系替换得到 t ,那么这两个字符串是同构的。 每个出现的字符都应当映射到另一个字符,同时不改变字符的顺序。不同字符不能映射到同一个字符…

Mysql教程(五):DQL学习

Mysql教程(五):DQL学习 DQL Data Query Language 数据查询语言,用来查询数据库中表的记录 1 基本语法 DQL查询语句,语法结构如下: SELECT字段列表 FROM表名列表 WHERE条件列表 GROUP BY分组字段列表 HAVI…

工时管理为何对项目如此重要?8Manage 带你读懂!

“时间就是金钱”,相信作为管理者都已经听腻了这话,但在项目管理中确实是真理。你要知道项目工时是会直接影响到项目费用成本的,不论项目工作是按小时还是按固定费用计费和付款,在一段工时内完成的工作越多,说明效率就…

myAgv的slam算法学习以及动态避障下篇

引言 在之前的一篇文章中有提到购入了一台myAGV,以树莓派4B为控制核心的移动机器人。上篇文章中向大家介绍了myAGV如何实现建图、导航以及静态避障,但我们深知,这只是机器人自主导航能力的基础。在实际应用场景中,机器人需要面对复…

【个人笔记】linux命令之ls

目录 Linux中一切皆文件ls命令常用参数常用命令lscpu lspci Linux中一切皆文件 理解参考:为什么说:Linux中一切皆文件? ls命令 ls(英文全拼: list directory contents)命令用于显示指定工作目录下之内容…

宝塔 30分钟部署免费在线客服系统

客服系统发布以来,一直有朋友询问如何在宝塔面板中安装部署,开始我一直认为参考 Linux 版的安装教程就可以了,一直没有专门写宝塔环境的教程。这段时间来咨询的朋友越来越多,经过了解,我才知道宝塔面板的普及率有多高&…

什么是Spring Actuator?它有什么优势?

目录 一、什么是Spring Actuator 二、Spring Actuator的应用场景 三、Spring Actuator的优势 一、什么是Spring Actuator Spring Actuator是Spring Boot提供的一个功能强大的管理和监控工具,用于监控和管理Spring Boot应用程序。它可以提供对应用程序的运行时信…

java实现身份证号码校验

二代身份证为18位,前六位为籍贯信息,7至14位为生日,最后一位校验前17位号码是否正确 校验规则为:前17位每一位乘以一个固定权重并相加然后除以11得到的余数,判断余数是否和校验的数相等 代码实现(支持15位…

leetcode 9 回文数

class Solution {public boolean isPalindrome(int x) {if(x < 0){return false;}int num x;int value 0;while(num > 0){value value * 10 num % 10;num num / 10;}return value x;} }

Enterprise:通过 App search 摄入数据

App Search 是 Elastic Enterprise Search 的一部分&#xff0c;Elastic Enterprise Search 是由 Elasticsearch 提供支持的内容搜索工具集合。 最初由 App Search 引入的一些功能&#xff08;例如网络爬虫&#xff09;现在可以直接通过企业搜索使用。 将这些功能与其他企业搜…

如何用DeepDiff测接口数据源变更?

开发同学最近变更了部分业务查询接口底层的数据源&#xff0c;希望测试同学能够针对这些接口进行一些回归验证&#xff0c;校验底层数据源更新前后业务查询接口返回的一致性&#xff0c;保证更新后对正常业务没有影响。 这个回归测试和一般接口测试有所区别&#xff0c;不仅仅…

混合背包(01+完全+多重背包大杂烩)

因为我们知道求解多重背包时&#xff0c;是将其进行二进制优化为01背包问题&#xff0c;那么我们就将01背包和多重背包看成一种情况&#xff0c;然后只要处理&#xff0c;完全背包和01背包问题即可&#xff08;详细看下方代码&#xff09; #include<bits/stdc.h> using n…

leetcode 965.单值二叉树

⭐️ 题目描述 &#x1f31f; leetcode链接&#xff1a;单值二叉树 思路&#xff1a; 让当前的根节点与左孩子节点与右孩子节点判断&#xff0c;若相等则继续向下分治&#xff0c;让左孩子与右孩子当作新的根节点继续判断&#xff0c;直到某个节点不相等。 1️⃣ 代码&#x…

JUC常用4大并发工具类详解

什么是 JUC JUC 就是 java.util.concurrent 包,这个包俗称 JUC,里面都是解决并发问题的一些东西,该包的位置位于 java 下面的 rt.jar 包下面。 JUC 中 4 大常用并发工具类 CountDownLatch CyclicBarrier Semaphore ExChanger CountDownLatch CountDownLatch,俗称闭锁,作用…

关于 PostgreSQL 删除数据库 - 命令行删除,报错数据库不存在,pgadmin 报错存在会话链接 导致无法删除数据库问题

序言 测试环境&#xff1a; Windows 10问题 笔者尝试过在 cmd 命令行&#xff0c;使用PostgreSQL 的 psql 工具登录 postgresql&#xff0c;删除某个有问题的数据库&#xff0c;准备新建重载该数据库时&#xff0c;发现 DROP DATABASE database_name &#xff0c;竟然报错该…

esp32-cam红外实时监控报警系统(巴发云和邮箱同时推送)

esp32-cam红外实时监控报警系统 设想-巴发云转折-照片数量限制代码避开巴发云照片限制邮箱的坑同时我的巴发云微信也受到了提醒报警&#xff0c;虽然没有图片显示。 设想-巴发云 我想做一个人体红外传感器发现人体报警&#xff0c;同时给我手机发报警提醒&#xff0c;同时发送…

《数据结构》数据结构概念,顺序表,链表

目录 1. 为什么学习数据结构&#xff1f; 2. 数据结构 2.1. 数据 2.2. 逻辑结构 2.3. 存储结构 2.4. 操作 3. 算法 3.1. 算法与程序 3.2. 算法与数据结构 3.3. 算法的特性 3.4. 如何评价一个算法的好坏 4. 线性表 4.1. 顺序表 4.2. 单向链表 4.3. 单向循环链表&…