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

目录

一、实验目的

二、问题描述

三、实验要求

四、算法思想

1.  基准算法

1.1 算法思想

1.2 代码

1.3 时间复杂度

2. 使用并查集的高效算法

2.1 算法思想

2.2 代码:

2.3 时间复杂度:

五、实验结果


实验目的

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.  基准算法

1.1 算法思想

        1)先dfs遍历图,得到连通分量个数N;

        2)遍历边集,对于每条边ei,先删除ei;

        3)再次dfs得到此时的连通分量个数num,

        4)如果num!=N,则ei为桥;否则不为桥。

        5)恢复ei,取下一条边ei+1,回到2)继续,直到遍历完全部边。

1.2 代码
int **k,*v,n,m,**br,brnum,N;
//邻接矩阵、访问位、点数、边数、是否为桥、桥数、
int *p,*d,*qiao;//并查集、点的深度、标记dfs2后是否为桥
string filename;//文件名void read1(){//初始化int i,a,b;ifstream file(filename.c_str());file>>n>>m;k=new int*[n];v=new int[n];br=new int*[n];brnum=0;for(i=0;i<n;i++){k[i]=new int[n];br[i]=new int[2];v[i]=0;br[i][0]=br[i][1]=0;for(int j=0;j<n;j++)k[i][j]=0;}for(i=0;i<m;i++){file>>a>>b;k[a][b]=1;k[b][a]=1;}file.close();
}void dfs1(int a){//dfs深度遍历int i;v[a]=1;for(i=0;i<n;i++)if(k[a][i]&&!v[i])dfs1(i);
}int count1(){//计算连通分量个数int i,num=0;for(i=0;i<n;i++)if(!v[i]){dfs1(i);num++;}return num;
}void base(){//基准法int i,j,a,b,num;ifstream file(filename.c_str());file>>n>>m;N=count1();for(i=0;i<m;i++){file>>a>>b;k[a][b]=0;//先删除该边k[b][a]=0;for(j=0;j<n;j++)v[j]=0;num=count1();if(num!=N){//判断是否为桥br[brnum][0]=a;//记录桥br[brnum][1]=b;brnum++;//桥个数增加}k[a][b]=1;//恢复该边k[b][a]=1;}file.close();
}void print1(){//因为实验对输出格式有要求int i,j,a,b;cout<<brnum<<endl;for(i=0;i<brnum-1;i++){//选择排序a=i;for(j=i+1;j<brnum;j++){if(br[j][0]<br[a][0]||(br[j][0]==br[a][0]&&br[j][1]<br[a][1]))//父端较小 或 父端相同、子端较小a=j;}b=br[a][0];br[a][0]=br[i][0];br[i][0]=b;b=br[a][1];br[a][1]=br[i][1];br[i][1]=b;}for(int i=0;i<brnum;i++){cout<<br[i][0]<<" "<<br[i][1]<<endl;}
}
1.3 时间复杂度

        n个点,m条边。需要遍历m条边,O(m),每次都需要count1一次,而count1由于是使用邻接矩阵储存边关系,最坏情况为O(n^2)。所以总的时间复杂度为O(m*n^2)。

        如果用邻接表,则count1的时间复杂度为O(n+m),总时间复杂度变为O(m(n+m))。

2. 使用并查集的高效算法

2.1 算法思想

        桥的等价意义:不在环上的边

        树是边数最小的无环图,当向树上添加任意一条顶点都在树上的边时,会形成环。桥不在环上,所以桥只能在图的生成树上。

        所以还是先构建生成树,然后不断dfs,不过dfs过程中顺便记录每个点的深度d[i]。

        再遍历所有边,每次遍历时:

                如果为生成树上的边则直接return。

                否则:求当前边两端点的最近公共祖先(LCA),过程中将路过的边(在环上)置为非桥边(q[i]==0);并根据LCA进行路径压缩compress(将环上除了LCA本身的点的父节点均设置为LCA)。

        这里以点带边,即q[i]==1表示以第i个点为尾的生成树上的边为桥,该边用(p[i],i)表示(p[i]为i在生成树上的父节点)。

2.2 代码:
void read2(){//读入文件信息并初始化…………
}void dfs2(int a,int b,int depth){//b is the ancestor of a…………
}void count2(){//生成生成树、并查集、深度集合等…………
}void compress(int x,int a){//路径压缩if(p[x]==a)//等于最近公共祖先return;else{int t=x;x=p[x];p[t]=a;compress(x,a);}
}void LCA(int a,int b){//对每条边的两点找最近公共祖先if(p[a]==b||p[b]==a)//在生成树上的边,直接返回return;else{int u=a,v=b,//保留原边的两端x=0,y=0;//判断a、b是否在while中执行了a=p[a]、b=p[b]操作,有执行才压缩,//避免其中一点是最近公共祖先时压缩导致该点父节点被自己覆盖while(1){if(d[a]>d[b]){//深度大的向上遍历qiao[a]=0;a=p[a];x=1;}else if(d[a]<d[b]){//深度大的向上遍历qiao[b]=0;b=p[b];y=1;}else if(a!=b){//深度相同但不同点,一起向上遍历qiao[a]=0;qiao[b]=0;a=p[a];b=p[b];x=y=1;}else break;//同个点,a=b=最近公共祖先}//此时a==bif(x)//路径压缩compress(u,a);if(y)compress(v,b);}
}
void better(){//并查集的高效算法int i,a,b;ifstream file(filename.c_str());//读入文件count2();//生成生成树、并查集、深度集合等file>>n>>m;for(i=0;i<m;i++){//遍历每一条边file>>a>>b;LCA(a,b);//求最近公共祖先}file.close();
}
void print2(){//打印输出……
}

     虽然压缩后不能再直接使用”if(p[a]==b||p[b]==a)“判断边(a,b)是否为原生成树上的边,但不影响结果。因为压缩的边都是非桥边,只不过会执行下面的while。但总体上压缩后效率还是提高了的。

2.3 时间复杂度:

        n个点,m条边。dfs构建生成树最坏情况下时间复杂度为O(n^2)。遍历m条边,每次查找最近公共祖先最差情况下要查找n次,时间复杂度为O(n),一次路径压缩最差情况时间复杂度也为O(n)。所以总时间复杂度为O(n*(m+n))。

实验结果

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

                                                  

        验证正确。

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

        mediumG.txt:

       对于largeG.txt文件,由于使用的是邻接矩阵,n太大,运行时内存不够分配,运行中断。

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

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

相关文章

高速公路安全新防线:护栏碰撞监测终端的应用与价值

​ ​​在现代化的高速公路管理体系中&#xff0c;安全始终放在第一位。随着道路上车辆密度的不断增加升&#xff0c;交通事故的风险也随之加剧&#xff0c;其中&#xff0c;护栏碰撞事故更是成为影响公路安全的一大隐患。为了有效减少此类事故的负面影响&#xff0c;提升应…

WebRTC笔记

一、 WebRTC的链接方式 1. 可以是浏览器之间的对等链接(全网状或完全分布式),那么数据就是在两个或多个浏览器之间流动 2. 可以是与媒体服务器的单一对等连接(集中混合式),这样的好处是可以扩展很大的会议,最大限度的减少新人加入时所需处理的工作量 二、 …

【嵌入式Linux】i.MX6ULL 复位中断服务函数的编写

文章目录 1. 复位中断服务函数0.1 禁止IRQ中断0.1.1 方式0.1.2 代码0.1.3 缩写说明0.1.4 PSTATE寄存器简介0.1.5 禁止IRQ中断的目的 1.1 关闭I/D Cache, MMU1.1.1 方式1.1.2 代码1.1.3 缩写说明1.1.4 关闭I/D Cache, MMU的目的 2.2 设置中断向量偏移2.2.1 方式2.2.2 代码2.2.3 …

卷积的通俗解释

以时间和空间两个维度分别理解卷积&#xff0c;先用文字来描述&#xff1a; 时间上&#xff0c;任何当前信号状态都是迄至当前所有信号状态的叠加&#xff1b;时间上&#xff0c;任何当前记忆状态都是迄至当前所有记忆状态的叠加&#xff1b;空间上&#xff0c;任何位置状态都…

python怎样自动提示

第一步、打开pycharm&#xff0c;如下图所示&#xff1a; 第二步、File→Power Save Mode&#xff0c;把下面如图所示的勾去掉&#xff1a; 第三步、去掉勾后&#xff0c;不再使用省电模式&#xff0c;新建一个python文件。输入单词前两个字母&#xff0c;就会自动提示了&#…

PAT B1041. 考试座位号

题目描述 每个PAT考生在参加考试时都会被分配两个座位号:一个是试机座位:另一个是考试座位。正常情况下&#xff0c;考生在入场时先得到试机座位号&#xff0c;入座进入试机状态后,系统会显示该考生的考试座位号,考试时考生需要换到考试座位就座。但有些考生迟到了&#xff0c;…

什么是空间数据

在数字孪生领域&#xff0c;需要汇聚、联接、融合地上地下、室内室外等多源异构数据&#xff0c;多源异构数据接入融合是一个复杂且关键的数据处理过程&#xff0c;它涉及将来自不同来源、具有不同格式和结构的数据进行有机整合&#xff0c;以生成一致、完整、可信且可用的数据…

为什么说大模型训练很难?

前言 在人工智能的浪潮中&#xff0c;大模型训练无疑是一股不可忽视的力量。然而&#xff0c;这背后的过程却充满了挑战与困难。今天&#xff0c;让我们一同揭开大模型训练的神秘面纱&#xff0c;探讨为何它值得您的关注与投入。 大模型训练的挑战 大模型训练之所以难&…

描述在React中集成第三方库(如Redux或React Router)的常见模式。

在React中集成第三方库&#xff0c;如状态管理库Redux或路由库React Router&#xff0c;通常遵循一些常见的模式和最佳实践。下面是一些集成这些库的步骤和模式&#xff1a; 集成Redux 安装Redux及相关包: 安装Redux及其中间件&#xff08;如redux-thunk或redux-saga&#xf…

【数据库中的存储桶】

存储桶是对象存储系统中的一个核心概念&#xff0c;起源于Amazon S3&#xff08;Simple Storage Service&#xff09;并被其他对象存储解决方案&#xff08;如MinIO、Google Cloud Storage等&#xff09;广泛采用。在传统的文件系统中&#xff0c;我们通常使用目录和子目录来组…

选择门店收银系统要考虑哪些方面?美业系统Java源码分享私

开店前的一个重要事件就是选择门店收银软件/系统&#xff0c;尤其是针对美容、医美等美业门店&#xff0c;一个优秀专业的系统十分重要&#xff0c;它必须贴合门店的经营需求&#xff0c;提供更全面、便捷、高效的管理功能&#xff0c;帮助提升门店的服务质量和经营效益。 以下…

Python笔记 文件的读取操作

1.open()打开函数 再Python&#xff0c;使用open函数&#xff0c;可以打开一个已经存在的文件&#xff0c;或者创建一个新文件&#xff0c;语法如下 open(name,mode,encoding) name:是要打开的文件名的字符串&#xff08;可以包含文件所在的具体路径&#xff09; mode&…

系统集成要求

系统集成要求 投标人需要支持通过标准化方式实现院内信息系统、信息平台、数据中心、运营管理等各系统之间通过标准化数据集建设实现各系统无缝集成。系统集成包含界面集成及数据层面的集成&#xff0c;为方便用户使用&#xff0c;高度集成临床工作站操作模块&#xff0c;比如消…

Apple-how can i use apple account sign in my app

If you’re enabling an App ID for the first time or for a new app, enable the App ID as a primary 在Apple Developer网站上启用Apple登录服务&#xff08;Sign in with Apple&#xff09;。 生成Sign in with Apple的Key&#xff0c;以及相关的App ID配置。 注册你的应…

【几何】多少正方形?

题目枚举边长为1边长为 2 \sqrt{2} 2 ​边长为 5 \sqrt{5} 5 ​边长为 8 \sqrt{8} 8 ​边长为 13 \sqrt{13} 13 ​ 扩展-使用代码来数1、定义点对象2、定义正方形对象3、初始化所有点4、调用完整代码 题目 多少正方形&#xff1f; 枚举 设每个横纵相邻点得间距为1&#xff0…

AMHS工程师的作用

1、AMHS Automatic Material Handling System&#xff0c;自动物料搬运系统在半导体厂中扮演着至关重要的角色。它通过自动化的方式&#xff0c;提高了晶圆厂的空间利用率、减少了机台的闲置时间、提升了生产效率以及产品良率。随着半导体制造工艺的不断进步&#xff0c;特别是…

线程池概念、线程池的不同创建方式、线程池的拒绝策略

文章目录 &#x1f490;线程池概念以及什么是工厂模式&#x1f490;标准库中的线程池&#x1f490;什么是工厂模式&#xff1f;&#x1f490;ThreadPoolExecutor&#x1f490;模拟实现线程池 &#x1f490;线程池概念以及什么是工厂模式 线程的诞生是因为&#xff0c;频繁的创…

3D Web轻量化引擎HOOPS Commuicator是如何创建AEC查看器的?

在当今数字化时代&#xff0c;建筑、工程和施工&#xff08;AEC&#xff09;行业正经历着一场技术革命。HOOPS Communicator&#xff0c;一款基于HOOPS Web平台的3D Web轻量化引擎&#xff0c;正是这场革命的先锋之一。本文将探讨HOOPS Communicator是如何创建AEC查看器的&…

【CentOS 7】深入指南:使用LVM和扩展文件系统增加root分区存储容量

【CentOS 7】深入指南&#xff1a;使用LVM和扩展文件系统增加root分区存储容量 大家好 我是寸铁&#x1f44a; 【CentOS 7】深入指南&#xff1a;使用LVM和扩展文件系统增加root分区存储容量 ✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 在运行CentOS 7服务器或虚拟机时&a…

用户 token 持久化

用户 token 持久化 业务背景&#xff1a;Token的有效期会持续一段时间&#xff0c;在这段时间内没有必要重复请求token&#xff0c;但是Vuex本身是基于内存的管理方式&#xff0c;刷新浏览器Token会丢失&#xff0c;为了避免丢失需要配置持久化进行缓存 基础思路&#xff1a;…