【算法沉淀】刷题笔记:并查集 带权并查集+实战讲解

 🎉🎉欢迎光临🎉🎉

🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀

🌟特别推荐给大家我的最新专栏《数据结构与算法:初学者入门指南》📘📘

希望能和大家一起学习!共同进步!

这是苏泽的个人主页可以看到我其他的内容哦👇👇

努力的苏泽icon-default.png?t=N7T8http://suzee.blog.csdn.net

当谈论并查集时,我们可以继续使用上述的动物园比喻来解释它的概念。

我们可以把并查集看作是一个动物园管理系统,帮助你管理动物们的归属关系。

在这个动物园中,每个动物都有一个独特的编号,代表一个独立的元素。一开始,每个动物都是独立的,没有与其他动物建立关系。

  1. 初始化(Init()函数)就像是给每个动物分配一个编号和一个独立的笼子。这样,它们就有了一个起始的归属地。

  2. 查找函数(Find()函数)就像是动物们在寻找自己所属的笼子。当你给一个动物的编号,它会告诉你它所在的笼子。这样,你可以快速找到任何动物所属的笼子。

  3. 合并集合函数(Join()函数)就像是把两个笼子合并在一起,让两个动物的集合变成一个更大的集合。当你把两个动物放在同一个笼子里,它们就成为了同一个集合,共享同一个归属地。

class UnionFind {private int[] parent;public UnionFind(int size) {parent = new int[size];for (int i = 0; i < size; i++) {parent[i] = i; // 每个动物初始时独立成为一个集合,自己是自己的根节点}}public int find(int x) {if (parent[x] != x) {parent[x] = find(parent[x]); // 使用路径压缩优化,将当前动物的父节点直接指向根节点}return parent[x]; // 返回动物所属的笼子(根节点)}public void join(int x, int y) {int rootX = find(x);int rootY = find(y);if (rootX != rootY) {parent[rootX] = rootY; // 将两个笼子合并,让一个根节点指向另一个根节点}}
}

历届试题 国王的烦恼
问题描述
C 国由 n nn 个小岛组成,为了方便小岛之间联络,C 国在小岛间建立了 m mm 座大桥,每座大桥连接两座小岛。两个小岛间可能存在多座桥连接。然而,由于海水冲刷,有一些大桥面临着不能使用的危险。

如果两个小岛间的所有大桥都不能使用,则这两座小岛就不能直接到达了。然而,只要这两座小岛的居民能通过其他的桥或者其他的小岛互相到达,他们就会安然无事。但是,如果前一天两个小岛之间还有方法可以到达,后一天却不能到达了,居民们就会一起抗议。

现在 C 国的国王已经知道了每座桥能使用的天数,超过这个天数就不能使用了。现在他想知道居民们会有多少天进行抗议。

输入格式
输入的第一行包含两个整数 n , m n, mn,m,分别表示小岛的个数和桥的数量。
接下来 m mm 行,每行三个整数 a , b , t a, b, ta,b,t,分别表示该座桥连接 a aa 号和 b bb 号两个小岛,能使用t天。小岛的编号从 1 开始递增。

输出格式
输出一个整数,表示居民们会抗议的天数。

样例输入
4 4
1 2 2
1 3 2
2 3 1
3 4 3

样例输出
2
样例说明
第一天后 2 和 3 之间的桥不能使用,不影响。
第二天后 1 和 2 之间,以及1和3之间的桥不能使用,居民们会抗议。
第三天后 3 和 4 之间的桥不能使用,居民们会抗议。

数据规模和约定
对于 30% 的数据,1 ≤ n ≤ 20 , 1 ≤ m ≤ 100 1\leq n \leq 20,1 \leq m \leq 1001≤n≤20,1≤m≤100;
对于 50% 的数据,1 ≤ n ≤ 500 , 1 ≤ m ≤ 10000 1 \leq n \leq 500,1 \leq m \leq 100001≤n≤500,1≤m≤10000;
对于 100% 的数据,1 ≤ n ≤ 10000 , 1 ≤ m ≤ 100000 , 1 ≤ a , b ≤ n , 1 ≤ t ≤ 100000 1 \leq n \leq 10000,1 \leq m \leq 100000,1\leq a, b \leq n, 1 \leq t \leq 1000001≤n≤10000,1≤m≤100000,1≤a,b≤n,1≤t≤100000。
 

首先,我们需要根据输入的桥的信息构建并查集。

对于每座桥,如果它的使用天数超过了指定的天数,我们将这两个小岛合并成同一个集合。如果它的使用天数没有超过指定的天数,说明这座桥可以使用,我们不需要对这两个小岛进行合并。

接下来,我们遍历所有的桥,对于每座桥,我们查找连接的两个小岛是否属于同一个集合。如果不属于同一个集合,说明这两个小岛之间没有其他路径可以到达,居民们会抗议的天数加一。

最后,输出居民们会抗议的天数即可。

import java.util.*;class UnionFind {private int[] parent;public UnionFind(int size) {parent = new int[size + 1];for (int i = 1; i <= size; i++) {parent[i] = i;}}public int find(int x) {if (parent[x] != x) {parent[x] = find(parent[x]);}return parent[x];}public void union(int x, int y) {int rootX = find(x);int rootY = find(y);if (rootX != rootY) {parent[rootX] = rootY;}}
}public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int m = scanner.nextInt();UnionFind uf = new UnionFind(n);for (int i = 0; i < m; i++) {int a = scanner.nextInt();int b = scanner.nextInt();int t = scanner.nextInt();if (t <= 2) {uf.union(a, b);}}int protestDays = 0;for (int i = 1; i <= n; i++) {if (uf.find(i) == i) {protestDays++;}}System.out.println(protestDays - 1);}
}

第二道题

问题描述
        小蓝国是一个水上王国, 有 2021 个城邦, 依次编号 1 到 2021。在任意两 个城邦之间, 都有一座桥直接连接。

        为了庆祝小蓝国的传统节日, 小蓝国政府准备将一部分桥装饰起来。

        对于编号为 a 和 b 的两个城邦, 它们之间的桥如果要装饰起来, 需要的费 用如下计算:

        找到 a 和 b 在十进制下所有不同的数位, 将数位上的数字求和。

        例如, 编号为 2021 和 922 两个城邦之间, 千位、百位和个位都不同, 将这些数位上的数字加起来是 (2+0+1)+(0+9+2)=14 。注意 922 没有千位, 千位看成 0 。

        为了节约开支, 小蓝国政府准备只装饰 2020 座桥, 并且要保证从任意一个 城邦到任意另一个城邦之间可以完全只通过装饰的桥到达。

        请问, 小蓝国政府至少要花多少费用才能完成装饰。

        提示: 建议使用计算机编程解决问题。

答案提交
        这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个整数, 在提交答案时只填写这个整数, 填写多余的内容将无法得分。

这道题有两个思路:

1.动态规划

思路讲解

首先,我们定义一个二维数组dp,其中dp[i][j]表示城邦i到城邦j之间需要装饰的费用。

然后,我们可以使用动态规划的思路来计算dp数组的值。对于每对城邦(i, j),我们可以通过考虑最后一段路径(i, k, j)来计算dp[i][j]的值,其中k是城邦j的前一个城邦。

具体地,我们可以遍历城邦k的所有可能取值(从1到2021),然后计算dp[i][j]的值。我们可以将dp[i][j]初始化为dp[i][k] + dp[k][j],然后再添加城邦kj之间的装饰费用cost(k, j)。其中cost(k, j)可以通过将城邦kj的编号转换为字符串,然后遍历字符串中的每个字符,将字符转换为数字并求和得到。

最后,我们需要计算小蓝国政府至少要花费的费用,即dp[1][2021]

public class Main {public static int calculateCost(int x, int y) {String strX = String.valueOf(x);String strY = String.valueOf(y);int cost = 0;for (char digit : strX.toCharArray()) {if (strY.contains(String.valueOf(digit))) {cost += Character.getNumericValue(digit);}}return cost;}public static void main(String[] args) {int[][] dp = new int[2022][2022];for (int i = 1; i <= 2021; i++) {for (int j = 1; j <= 2021; j++) {if (i != j) {dp[i][j] = calculateCost(i, j);}}}for (int k = 1; k <= 2021; k++) {for (int i = 1; i <= 2021; i++) {for (int j = 1; j <= 2021; j++) {if (i != j && i != k && j != k) {dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[k][j]);}}}}int answer = dp[1][2021];System.out.println(answer);}
}

2.并查集

题目将城堡看作连通带权无向图,其中城堡的编号表示图的节点,城堡之间的桥梁装饰费用表示图的边权。

首先,我们定义一个并查集数据结构,用于合并城堡所属的连通分量。

然后,我们遍历所有的桥梁,计算每座桥梁的装饰费用,并将费用作为边权存储在一个二维数组dp中。

接下来,我们使用并查集的思想,将连接费用为0的城堡合并到同一个连通分量中。

最后,我们计算所有城堡到第一个城堡的装饰费用,即累加每个连通分量中的最小边权。

这样,我们就可以得到小蓝国政府至少要花费的费用。

import java.util.Arrays;public class Main {public static class UnionFind {private int[] parent;private int[] rank;public UnionFind(int n) {parent = new int[n];rank = new int[n];Arrays.fill(rank, 1);for (int i = 0; i < n; i++) {parent[i] = i;}}public int find(int x) {if (parent[x] != x) {parent[x] = find(parent[x]);}return parent[x];}public void union(int x, int y) {int rootX = find(x);int rootY = find(y);if (rootX != rootY) {if (rank[rootX] > rank[rootY]) {parent[rootY] = rootX;} else if (rank[rootX] < rank[rootY]) {parent[rootX] = rootY;} else {parent[rootY] = rootX;rank[rootX]++;}}}}public static int calculateCost(int x, int y) {String strX = String.valueOf(x);String strY = String.valueOf(y);int cost = 0;for (char digit : strX.toCharArray()) {if (strY.contains(String.valueOf(digit))) {cost += Character.getNumericValue(digit);}}return cost;}public static void main(String[] args) {int n = 2021;UnionFind uf = new UnionFind(n + 1);int[][] dp = new int[n + 1][n + 1];// 构建并查集for (int i = 1; i <= n; i++) {for (int j = i + 1; j <= n; j++) {int cost = calculateCost(i, j);dp[i][j] = cost;dp[j][i] = cost;if (cost == 0) {uf.union(i, j);}}}// 合并连通分量int[] set = new int[n + 1];Arrays.fill(set, -1);for (int i = 1; i <= n; i++) {int root = uf.find(i);if (set[root] == -1) {set[root] = i;}}// 计算最小装饰费用int answer = 0;for (int i = 1; i <= n; i++) {if (set[i] != -1) {answer += dp[1][set[i]];}}System.out.println(answer);}
}

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

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

相关文章

Day13:信息打点-JS架构框架识别泄漏提取API接口枚举FUZZ爬虫插件项目

目录 JS前端架构-识别&分析 JS前端架构-开发框架分析 前端架构-半自动Burp分析 前端架构-自动化项目分析 思维导图 章节知识点 Web&#xff1a;语言/CMS/中间件/数据库/系统/WAF等 系统&#xff1a;操作系统/端口服务/网络环境/防火墙等 应用&#xff1a;APP对象/API接…

多模态大语言模型的ai反馈增强机器人操作研究

本研究关注于利用大语言模型&#xff08;LLMs&#xff09;提供的自动化偏好反馈来增强决策过程 ○ 提出了一种多模态LLM&#xff0c;称为CriticGPT&#xff0c;可以理解机器人操作任务中的轨迹视频&#xff0c;并提供分析和偏好反馈 ○ 从奖励建模的角度验证了CriticGPT生成的…

使用 MongoDB Atlas 无服务器实例更高效地开发应用程序

使用 MongoDB Atlas无服务器实例更高效地开发应用程序 身为开发者&#xff0c;数据库并不一定需要您来操心。您可不想耗费时间来预配置集群或调整集群大小。同样地&#xff0c;您也不想操心因未能正确扩展而导致经费超标。 MongoDB Atlas 可为您提供多个数据库部署选项。虽然…

【javascript】快速入门javascript

本文前言及说明 适合学过一门语言有一定基础的人看。 省略最初学习编程时的各种编程重复的基础知识。 javascript简介 编程语言&#xff08;主前端&#xff09; 用途&#xff1a;主web前后端&#xff0c;游戏&#xff0c;干别人网站 优点&#xff1a;速度快&#xff0c;浏…

一文扫盲:室内导航系统的应用场景和技术实现(入门级)

hello&#xff0c;我是贝格前端工场&#xff0c;之间搞过一些室内导航项目&#xff0c;有2D也有3D的&#xff0c;算是有些经验&#xff0c;这里给大家分享一下室内导航的基本尝试&#xff0c;欢迎老铁们点赞、关注&#xff0c;如有需求可以私信我们。 一、室内导航是什么 室内…

Vue开发实例(十)Tabs标签页打开、关闭与路由之间的关系

创建标签页 一、创建标签页二、点击菜单展示新标签页1、将标签数据作为全局使用2、菜单点击增加标签页3、处理重复标签4、关闭标签页 三、点击标签页操作问题1&#xff1a;点击标签页选中菜单进行高亮展示问题2&#xff1a;点击标签页路由也要跳转 四、解决bug 先展示最终效果 …

Android 基础入门 基础简介

1. 观察App运行日志 2.Android 开发设计的编程语言 koltin Java c c 3.工程目录结构 4.Gradle 5.build.gradle 文件解析 plugins {id("com.android.application")//用了哪些插件 主配置文件版本控制 所以这里不用写版本 }android {namespace "com.tiger.myap…

基于springboot+vue的二手车交易系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

C++进阶(二) 多态

一、多态的概念 多态的概念&#xff1a;通俗来说&#xff0c;就是多种形态&#xff0c; 具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会 产生出不同的状态。举个栗子&#xff1a;比如买票这个行为&#xff0c;当普通人买票时&#xff0c;是全价买票&#xff1b;学…

Java中的List

List集合的特有方法 方法介绍 方法名描述void add(int index,E element)在此集合中的指定位置插入指定的元素E remove(int index)删除指定索引处的元素&#xff0c;返回被删除的元素E set(int index,E element)修改指定索引处的元素&#xff0c;返回被修改的元素E get(int inde…

动态规划5,粉刷房子,买卖股票的最佳时期

粉刷房子 思路&#xff1a; 1.经验题目要求 dp[i][0] 表示&#xff1a;粉刷到 i 位置的时候&#xff0c;最后一个位置粉刷上红色&#xff0c;此时的最小花费。 dp[i][1] 表示&#xff1a;粉刷到 i 位置的时候&#xff0c;最后一个位置粉刷上蓝色&#xff0c;此时的最小花费。…

mybatis开发一个分页插件、mybatis实现分页、mybatis拦截器

mybatis开发一个分页插件、mybatis实现分页、mybatis拦截器 通过官网的mybatis插件说明可知&#xff0c;我们可以通过拦截器进行开发一个插件。 例如这样的&#xff1a; UserMapper mapper sqlSession.getMapper(UserMapper.class);// 开始分页MagicPage.startPage(1, 3);//…

Linux:线程的概念

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》《Linux》 文章目录 前言一、线程的概念线程代码的简单示例 总结 前言 本文是对于线程概念的知识总结 一、线程的概念 在课本上&#xff0c;线程是比进程更轻量级的一种指向流 或 线程是在…

VS Code 的粘性滚动预览 - 类似于 Excel 的冻结首行

VS Code 的粘性滚动预览 - 类似于 Excel 的冻结首行功能&#xff0c;即滚动 UI 显示当前源代码范围。便于在代码行数比较多的时候更好的知道自己所在的位置。粘性滚动UI 显示用户在滚动期间所处的范围&#xff0c;将显示编辑器顶部所在的类/接口/命名空间/函数/方法/构造函数&a…

理解这几个安全漏洞,你也能做安全测试

01 短信炸弹 1、漏洞描述 短信轰炸攻击是常见的一种攻击&#xff0c;攻击者通过网站页面中所提供的发送短信验证码的功能处&#xff0c;通过对其发送数据包的获取后&#xff0c;进行重放&#xff0c;如果服务器短信平台未做校验的情况时&#xff0c;系统会一直去发送短信&…

JVM内部世界(内存划分,类加载,垃圾回收)

&#x1f495;"Echo"&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;JVM内部世界(内存划分,类加载,垃圾回收) 关于JVM的学习主要掌握三方面: JVM内存区的划分类加载垃圾回收 一.JVM内存区的划分 当一个Java进程开始执行时,JVM会首先向操作系统申…

实例驱动计算机网络

文章目录 计算机网络的层次结构应用层DNSHTTP协议HTTP请求响应过程 运输层TCP协议TCP协议面向连接实现TCP的三次握手连接TCP的四次挥手断开连接 TCP协议可靠性实现TCP的流量控制TCP的拥塞控制TCP的重传机制 UDP协议 网际层IP协议&#xff08;主机与主机&#xff09;IP地址的分类…

【创作回顾】17个月峥嵘创作史

#里程碑专区#、#创作者纪念日# 还记得 2022 年 10 月 05 日&#xff0c;我在CSDN撰写了第 1 篇博客——《关于测试工程师瓶颈和突围的一个思考》&#xff0c;也是我在全网发布的第一篇技术文章。 回想当时&#xff0c;这一篇的诞生过程并不轻松&#xff0c;不像是一篇网络文章…

【计算机网络】深度学习HTTPS协议

&#x1f493; 博客主页&#xff1a;从零开始的-CodeNinja之路 ⏩ 收录文章&#xff1a;【计算机网络】深度学习HTTPS协议 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 一:HTTPS是什么二:HTTPS的工作过程三:对称加密四:非对称加密五:中间人攻击1…

【web | CTF】BUUCTF [HCTF 2018]WarmUp

天命&#xff1a;这题本地php代码是无法复现的 首先打开网站&#xff0c;啥也没有&#xff0c;查看源码 发现文件&#xff0c;打开访问一下看看&#xff0c;发现是代码审计 <?phphighlight_file(__FILE__);class emmm{public static function checkFile(&$page){$whit…