算法设计与分析 实验5 并查集法求图论桥问题

目录

一、实验目的

二、问题描述

三、实验要求

四、实验内容

(一)基准算法

(二)高效算法

五、实验结论


一、实验目的

        1. 掌握图的连通性。

        2. 掌握并查集的基本原理和应用。

二、问题描述

        在图论中,一条边被称为“桥”代表这条边一旦被删除,这个图的连通块数量会增加。等价地说,一条边是一座桥当且仅当这条边不在任何环上,一个图可以有零或多座桥。现要找出一个无向图中所有的桥,基准算法为:对于图中每条边uv,删除该边后,运用BFS或DFS确定u和v是否仍然连通,若不连通,则uv是桥。应用并查集设计一个比基准算法更高效的算法,不要使用Tarjan算法。

                                             

                    图1 没有桥的无向连通图              图2 有16个顶点和6个桥的图(桥以红色线段标示)

三、实验要求

        1. 实现上述基准算法。

        2. 设计的高效算法中必须使用并查集,如有需要,可以配合使用其他任何数据结构。

        3. 用图2的例子验证算法的正确性,该图存储在smallG.txt中,文件中第1行是顶点数,第2行是边数,后面是每条边的两个端点。

        4. 使用文件mediumG.txt和largeG.txt中的无向图测试基准算法和高效算法的性能,记录两个算法的运行时间。

        5. 实验课检查内容:对于smallG.txt、mediumG.txt、largeG.txt中的无向图,测试高效算法的输出结果和运行时间,检查该代码,限用C或C++语言编写。其中smallG.txt和mediumG.txt为必做内容,运行时间在4分钟内有效,直接在终端输出结果和运行时间。以smallG.txt为例,输出如下:

6

0 1

2 3

2 6

6 7

9 10

12 13

0.002

        其中,第一行的6表示桥数,接下来的6行分别是6座桥的两个端点,小端点在前,大端点在后,6座桥按照端点从小到大的顺序输出,最后一行的0.002为整个main函数的运行时间,单位为秒。

四、实验内容

(一)基准算法

1. 算法描述:

        根据桥的定义,我们可以知道,一条边(𝑢, 𝑣)是桥,当且仅当删除边(𝒖, 𝒗)后,图的连通块数量会增加。我们可以枚举整个边集,并依次检查在删除每条边后连通块数量是否增加。具体我们可以用以下方式实现基准算法:

                使用深度优先搜索算法𝑑𝑓𝑠获取整张图的连通块个数𝑁。

                遍历整张图边集,对于每条边(𝑢, 𝑣),首先在图中将其删除。

                再次使用深度优先搜索算法𝑑𝑓𝑠获取整张图的连通块个数𝑁′。

                若𝑁′>𝑁,则(𝑢, 𝑣)为桥,否则(𝑢, 𝑣)不为桥。

                将边(𝑢, 𝑣)恢复。回到步骤 2,直至遍历完全部边集。

2、伪代码

3. 复杂度分析

        (1)时间复杂度:不妨设图中点的数量为𝑛,边的个数为𝑚。使用𝐷𝐹𝑆的时间复杂度为

𝑂(𝑛 + 𝑚)。又因为一共有𝑚条边需要进行判断,所以一共要做𝑚次𝐷𝐹𝑆,总时间复杂度为𝑂(𝑚𝑛 + 𝑚2)。

                对于稀疏图,因为有𝑚 ∝ 𝑛,所以该算法时间复杂度可表示为𝑂(𝑛2);

                对于稠密图,因为有𝑚 ∝ 𝑛2,所以该算法时间复杂度可表示为𝑂(𝑛4)。

       (2)空间复杂度:我们用邻接表对整张图进行储存,空间复杂度一共为𝑂(𝑛 + 𝑚)。

4. 数据测试分析

              我们分别取点的数量𝑛 = 1000、2000、3000、4000 和 5000,边的数量𝑚 = 𝑛作为稀疏,边的数量𝑚 =n*(n-1)/2作为稠密图对算法进行测试。

              为降低偶然性,我们对每组数据重复测试 10 次再取平均值

1.1 稀疏图基准算法运行时间表

点的数量𝑛

1000

2000

3000

4000

5000

实际运行时间(ms)

16.5215

77.4551

197.404

397.095

650.526

理论运行时间(ms)

16.5215

77.32

196.641

388.781

638.223

1.2 稠密图基准算法运行时间表

点的数量𝑛

100

200

300

400

500

实际运行时间(ms)

219.495

4039.62

22930.6

67342

190571

理论运行时间(ms)

219.495

3511.92

19779.095

62190.72

170184.375

        从上表和上图可以看出,无论是在稀疏图还是在稠密图中,算法实际运行的时间和理论运行时间曲线拟合效果良好

5. 基准算法优化

       一次删边操作影响的只是其中一个连通分量,不需要对全图进行𝐷𝐹𝑆 。所以我们在删除边之后,只对所删除边的其中一个端点做𝑫𝑭𝑺 :

如果在深度优先搜索过程中搜索到另一结点,则说明边的两个端点在同一连通分支,该边不是桥。

若从一个端点出发没有搜到另一个端点,则说明边的两个端点不在在同一连通分支,该边是桥。


伪代码描述:

耗时对比:

2.1 稀疏图中基准算法及优化基准算法运行时间

点的数量𝑛

1000

2000

3000

4000

5000

未优化(ms)

15.275

84.8875

222.129

433.341

720.145

判断优化(ms)

9.03036

39.3281

88.6593

167.861

267.835

2.2 稠密图中基准算法及优化基准算法运行时间

点的数量𝑛

100

200

300

400

500

未优化(ms)

219.495

4039.62

22930.6

67342

190571

判断优化(ms)

16.631

250.045

1301.25

4629.83

10228.2

        在进行判断优化的基础上,在稀疏图中,代码运行效率提升了50%,且点数越多,优化效果越明显;在稠密图中,提升效果则更加明显

(二)高效算法

1. 数据结构介绍

并查集

        并查集是一种树型的数据结构,可以解决局部联通问题。并查集把有联系的元素放入同一个集合,用集合中的一个“有代表性”的元素来表示整个集合,其中集合内部的关系是用一个𝑓𝑎指针来维护。并查集常见的操作有查询与合并这两种操作。

        查询操作:查询即查询当前两元素是否在同一集合中。我们可以通过递归层层向上访问,直至访问到根节点。若两元素的根节点相同,则说明两元素在同一集合中。否则不在同一集合中。

        合并操作:合并即将不在同一集合中的两个子集合合并为一个集合。对于两个需要合并的元 素,我们首先通过查询得出两个集合的根节点,然后修改其中一个根节点的𝑓𝑎指针,使其指向另一集合的根节点即可

路径压缩

        随着集合元素变多,链越来越长,我们想要从底部找到根节点就需要经过层层递 归,这使得  操作变得越来越难。既然我们只关心一个元素对应的根节点,那么我们就考虑将集合中每个元素的𝑓𝑎指针直接指向根节点。

        实现方式就是在查询的时候,把沿途的每个节点的父节点都设置为根节点,这样就可以的降低查询时递归向上的查询深度

STL

       向量vector,一个大小可动态变化的顺序数组容器

       vector 容器一方面可以动态的分配空间,比一般的数组更合理使用空间;另外它有很多基本函数,如push_back()函数类似队列中的push()函数,size()可以直接返回当前容器长度。因为 vector 可以更方便的使用函数调用和管理空间,高效算法构建邻接表就通过 vector 实现。

对于大数据量级下的图结构,如果使用临近矩阵进行存储,会造成内存溢出,因此也必须使用邻接表进行存储。

2. LCA算法-引入最近公共祖先

       在一棵没有环的树上,除根节点外每个节点都有其父节点和祖先节点,最近公共祖先就是两个节点在这棵树上深度最大的公共祖先节点。

       LCA(Least Common Ancestors),用于求解两个节点的最近公共祖先的算法。其可用于最短路径计算,连通性判断,图论问题等。

如上图,4和6的最近公共祖先为5

       在本实验中,我们可以利用最近公共祖先(LCA)算法找出生成森林中的环边,即把找LCA 时经过的边删除,生成森林中剩余的边即为桥。

3. 算法思想

       根据桥的定义和图论的相关知识,我们可以知道,一条边是桥当且仅当这条边不在任何环上才成立。那么我们可以用排除法得到图中的桥,即用 “总边 - 环边”。

         又由图论知识可以得出,树是边数最大的无环图,若向树上添加任意一条边时,必然会形成环,所以我们只需找出生成树中的环边,除去这些即为桥。

       基于这一想法,可以先构建生成树

我们接着枚举不在生成森林上的所有边,然后可以利用最近公共祖先(LCA)算法找出生成森林中的环边,即把找LCA 时经过的边删除,生成森林中剩余的边即为桥。

       对于下图来说,蓝色的边是非生成森林中的边,我们对该边左右两个节点求LCA:首先比较两个节点的深度,将深度大的节点跳转到其父节点,并删除跳转时经过的边(图中显示为红色),重复这个过程直到两个点跳转到同一个点,即跳转到它们的 LCA。可以看到,红颜色的边就是利用LCA 算法找出的生成森林中的环边。但由于有些树的路径繁长,可通过并查集进行路径压缩提高搜索效率

4. 算法实现

并查集-朴素并查集实现求图的桥算法实现

查询操作和路径压缩

合并操作  算法优化

        合并操作算法优化—按秩合并,通过size向量,记录每个集合的大小,并在合并时选择将较小的集合合并到较大的集合上,从而实现有效控制树的高度,提高并查集的查找效率

LCA算法实现

       并查集+LCA算法求解桥问题的算法实现,首先对整个图分为不同连通块进行深度优先搜索,随后通过LCA寻找最近公共祖先,对形成环的边进行分析处理,最后剩下边的数量即为桥的数量。

       LCA求解最近公共祖先

路径压缩

5. 复杂度分析

        (1)时间复杂度:最坏情况下当生成树是一条链的时候,此时的时间复杂度为𝑂(𝑛),故总时间复杂度为𝑂(𝑚𝑛)

        对于稀疏图,因为有𝑚 ∝ 𝑛,所以该算法时间复杂度可表示为𝑂(𝑛2);对于稠密图,因为有𝑚 ∝ 𝑛2,所以该算法时间复杂度可表示为𝑂(𝑛3)。

       对于大数据量级下的查找操作,经过并查集的路径压缩,很快需要查找的节点基本上父节点大部分都已经被设置为最近公共祖先(LCA)。此时,查找的时间会接近O ( 1 ) ,则最终的时间复杂度将接近O(m)

        (2)空间复杂度:我们用邻接表对整张图进行储存,空间复杂度一共为𝑂(𝑛 + 𝑚)。

6. 数据测试分析

        我们分别取点的数量𝑛 = 1000、2000、3000、4000 和 5000,边的数量𝑚 = 𝑛作为稀疏,边的数量𝑚 =n*(n-1)/2作为稠密图对算法进行测试。

        为降低偶然性,我们对每组数据重复测试 10 次再取平均值

2.1 稀疏图中高效算法运行时间

点的数量𝑛

1000

2000

3000

4000

5000

实际运行时间

4.0968

5.9614

7.9826

9.2091

17.4451

理论运行时间

4.0968

16.3872

36.8712

65.5488

102.42

2.2 稠密图中高效算法运行时间

点的数量𝑛

100

200

300

400

500

实际运行时间

3.7533

22.5624

62.2405

162.192

212.828

理论运行时间

3.7533

30.0264

101.339

240.211

469.163

        由于𝑂(𝑛2)是算法在稀疏图的理论上界,是在最坏的情况下才会出现的结果,所以实际运行时间曲线要低于理论运行时间曲线,即 LCA 算法在稀疏图中时间复杂度的理论上界为𝑂(𝑛2)。由于𝑂(𝑛3)是算法在稠密图的理论上界,是在生成森林为一条链时才会出现的结果,所以实际运行时间曲线要低于理论运行时间曲线,即 LCA 算法在稠密图的时间复杂度的理论上界为𝑂(𝑛2)。

三) 综合对比分析

        将结果综合分析,如下:

图中各种算法运行时间

点的数量

1000

2000

3000

4000

5000

基准算法

16.5215

77.4551

197.404

397.095

650.526

高效算法

0.43826

0.86072

1.11762

1.31792

1.71322

 稠密图中各种算法运行时间

点的数量

1000

2000

3000

4000

5000

基准算法

219.495

4039.62

22930.6

67342

190571

高效算法

0.43826

0.86072

1.11762

1.31792

1.71322

       用并查集结合LCA算法的程序运行时间无论是在稀疏图还是在稠密图,都远低于基准算法所消耗的时间

对附录中的三个图文件进行运行得出:

图文件

基准算法

高效算法

桥个数

smallG.txt

0.002s

0.00017s

6

mediumG.txt

0.124s

0.00020s

3

largeG.txt

Time-out

0.98503s

8

五、实验结论

实验总结

在本次实验中,我使用了基准算法、并查集算法结合实现了在无向图中找出所有的桥,并对上述算法提出了不同的优化方式。之后对各个算法进行多次测试与比较,在算法的运行时间上我们得出以下结果:

LCA 算法+并查集算法   <<<< 基准算法

       所以对于找出一个无向图中所有桥的问题,选好解决算法十分重要

实验思考

        在本次实验中,我使用了大量STL容器,因此在编译时添加O3优化,可以节约程序运行时间

        在使用生成森林优化的时候,最好使用 bfs 来构建生成森林。这是因为使用 dfs 构建的生成森林的深度通常会非常的深(接近一条链,也就是我们前面所说的最坏情况),从而导致求 LCA 时需要遍历的点非常的多,降低了程序的运行效率。

经过测试,使用bfs代替dfs可以替身近40%的效率

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IDEA发疯导致maven下载回来的jar不完整zip END header not found

IDEA发疯导致maven下载回来的jar不完整zip END header not found 具体报错 java: 读取D:\mavenRepository\com\alibaba\druid-spring-boot-starter\1.2.23\druid-spring-boot-starter-1.2.23.jar时出错; zip END header not foundjava: java.lang.RuntimeException: java.io.…

Python视觉轨迹几何惯性单元超维计算结构算法

&#x1f3af;要点 &#x1f3af;视觉轨迹几何惯性单元超维计算结构算法 | &#x1f3af;超维计算结构视觉场景理解 | &#x1f3af;超维计算结构算法解瑞文矩阵 | &#x1f3af;超维矢量计算递归神经算法 &#x1f36a;语言内容分比 &#x1f347;Python蒙特卡罗惯性导航 蒙…

【感谢告知】本账号内容调整,聚焦于Google账号和产品的使用经验和问题案例分析

亲爱的各位朋友&#xff1a; 感谢您对本账号的关注和支持&#xff01; 基于对朋友们需求的分析和个人兴趣的转变&#xff0c;该账号从今天将对内容做一些调整&#xff0c;有原来的内容改为Google&#xff08;谷歌&#xff09;账号和产品的使用经验&#xff0c;以及相关问题的…

LeetCode 744, 49, 207

目录 744. 寻找比目标字母大的最小字母题目链接标签思路代码 49. 字母异位词分组题目链接标签思路代码 207. 课程表题目链接标签思路代码 744. 寻找比目标字母大的最小字母 题目链接 744. 寻找比目标字母大的最小字母 标签 数组 二分查找 思路 本题比 基础二分查找 难的一…

《python程序语言设计》2018版第5章第53题利用turtle绘制sin和cos函数 sin蓝色,cos红色和52题类似

直接上题和代码 5.53 &#xff08;Turtle&#xff1a;绘制sin和cos函数&#xff09;编写程序绘制蓝色的sin函数和红色的cos函数。 代码和结果 turtle.speed(10) turtle.penup() # sin 用蓝色 turtle.color("blue") #这道题和上道题一样&#xff0c;先把turtle放到起始…

pandas读取CSV格式文件生成数据发生器iteration

背景 数据集标签为csv文件格式&#xff0c;有三个字段column_hander [‘id’, ‘boneage’, ‘male’]&#xff0c;需要自己定义数据集。文件较大&#xff0c;做一个数据发生器迭代更新数据集。 实现模板 在Pandas中&#xff0c;可以使用pandas.read_csv函数读取CSV文件&…

官网首屏:激发你的小宇宙和第六感,为了漂亮,干就完了。

官网的首屏是指用户打开网站后首先看到的页面&#xff0c;通常是整个网站最重要的一部分。首屏的设计和内容对于吸引用户的注意力、传达品牌形象和价值、促使用户继续浏览和进行交互非常关键。以下是官网首屏的重要性的几个方面&#xff1a; 1. 第一印象&#xff1a; 首屏是用…

Redis官方可视化管理工具

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl RedisInsight是一个Redis可视化工具&#xff0c;提供设计、开发和优化 Redis 应用程序的功能。RedisInsight分为免费的社区版和一个付费的企业版&#xff0c;免费版具有基本…

文心一言 VS 讯飞星火 VS chatgpt (297)-- 算法导论22.1 1题

一、给定有向图的邻接链表&#xff0c;需要多长时间才能计算出每个结点的出度(发出的边的条数)&#xff1f;多长时间才能计算出每个结点的入度(进入的边的条数)&#xff1f;如果要写代码&#xff0c;请用go语言。 文心一言&#xff1a; 计算出度 对于有向图的邻接链表表示&a…

C++ 引用——常量引用

作用&#xff1a;常量引用主要用来修饰形参&#xff0c;防止误操作 在函数形参列表中&#xff0c;可以加const修饰形参&#xff0c;防止形参改变实参 示例&#xff1a; 运行结果&#xff1a;

【Linux】进程优先级 + 环境变量

前言 在了解进程状态之后&#xff0c;本章我们将来学习一下进程优先级&#xff0c;还有环境变量等。。 目录 1.进程优先级1.1 为什么要有优先级&#xff1f; 2.进程的其他概念2.1 竞争性与独立性2.2 并行与并发2.3 进程间优先级的体现&#xff1a;2.3.1 O(1) 调度算法&#xf…

202406 CCF-GESP Python 四级试题及详细答案注释

202406 CCF-GESP Python 四级试题及详细答案注释 1 单选题(每题 2 分,共 30 分)第 1 题 小杨父母带他到某培训机构给他报名参加CCF组织的GESP认证考试的第1级,那他可以选择的认证语言有几种?( ) A. 1 B. 2 C. 3 D. 4答案:C解析:目前CCF组织的GESP认证考试有C++、Pyth…

Element中的表格组件Table和分页组件Pagination

简述&#xff1a;在 Element UI 中&#xff0c;Table组件是一个功能强大的数据展示工具&#xff0c;用于呈现结构化的数据列表。它提供了丰富的特性&#xff0c;使得数据展示不仅美观而且高效。而Pagination组件是一个用于实现数据分页显示的强大工具。它允许用户在大量数据中导…

【OJ】运行时错误(Runtime Error)导致递归爆栈问题

在进行OJ赛时&#xff0c; 题目&#xff1a;给你一个整数n&#xff0c;问最多能将其分解为多少质数的和。在第一行输出最多的质数数量k,下一行输出k个整数&#xff0c;为这些质数。 出现运行时错误 代码如下&#xff1a; def main():# code heren int(eval(input()))list …

RabbitMQ中常用的三种交换机【Fanout、Direct、Topic】

目录 1、引入 2、Fanout交换机 案例&#xff1a;利用SpringAMQP演示Fanout交换机的使用 3、Direct交换机 案例&#xff1a;利用SpringAMQP演示Direct交换机的使用 4、Topic交换机 案例&#xff1a;利用SpringAMQP演示Topic交换机的使用 1、引入 真实的生产环境都会经过e…

Apache Seata分布式事务原理解析探秘

本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 前言 fescar发布已有时日&#xff0c;分布式事务一直是业界备受关注的领域&#xff0c;fesca…

【Mysql】记录MySQL中常见的错误代码及可能原因

希望文章能给到你启发和灵感&#xff5e; 如果觉得文章对你有帮助的话&#xff0c;点赞 关注 收藏 支持一下博主吧&#xff5e; 阅读指南 开篇说明一、基础环境说明1.1 硬件环境1.2 软件环境 二、常见的问题2.1 连接和认证相关2.2 权限相关2.3 表和数据操作相关2.4 资源限制和…

我使用HarmonyOs Next开发了b站的首页

1.实现效果展示&#xff1a; 2.图标准备 我使用的是iconfont图标&#xff0c;下面为项目中所使用到的图标 3. 代码 &#xff08;1&#xff09;Index.ets&#xff1a; import {InfoTop} from ../component/InfoTop import {InfoCenter} from ../component/InfoCenter import…

文章解读与仿真程序复现思路——太阳能学报EI\CSCD\北大核心《计及电-热-氢负荷与动态重构的主动配电网优化调度》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

Linux 搭建 Kafka 环境 - 详细教程

目录 一. Kafka介绍 1. 应用场景 2. 版本对比 二. Kafka安装 1. 前置环境 &#xff08;1&#xff09;安装JDK 2. 软件安装 &#xff08;3&#xff09;环境变量配置 &#xff08;3&#xff09;服务启动 三. Console测试 基础命令 &#xff08;1&#xff09;列出Kafk…