【数据结构与算法】最小生成树与最短路径

news2024/12/25 9:20:24

🔥 本文由 程序喵正在路上 原创,CSDN首发!
💖 系列专栏:数据结构与算法
🌠 首发时间:2022年11月21日
🦋 欢迎关注🖱点赞👍收藏🌟留言🐾
🌟 一以贯之的努力 不得懈怠的人生

阅读指南

  • 最小生成树
    • 生成树
    • 最小生成树(最小代价树)
    • Prim 算法(普利姆)
    • Kruskal 算法(克鲁斯卡尔)
  • 最短路径
    • BFS 求无权图的单源最短路径
    • Dijkstra 算法
    • Floyd 算法
    • 总结

最小生成树

生成树

连通图的生成树是包含图中全部顶点的一个极小连通子图(边尽可能少,但要保持连通)

若图中顶点数为 n n n,则它的生成树有 n − 1 n - 1 n1 条边。对生成树而言,若砍去它的一条边,则会变成非连通图,若加上一条边则会形成一个回路

在这里插入图片描述

最小生成树(最小代价树)

我们来看一个问题:有下图这么几个地方构成的图,图中每条边上的数字是修路的费用,然后要我们规划道路,让所有地方都连通,并且成本要尽可能低

在这里插入图片描述

其实要我们找的,就是这个图的最小生成树

对于一个带权连通无向图 G = ( V , E ) G = (V, E) G=(V,E),生成树不同,每棵树的权(即树中所有边上的权值之和)也可能不同。设 R R R G G G 的所哟生成树的集合,若 T T T R R R 中边的权值之和最小的生成树,则 T T T 称为 G G G 的最小生成树( M i n i m u m − S p a n n i n g − T r e e , M S T Minimum-Spanning-Tree, MST MinimumSpanningTree,MST

注意:

  1. 最小生成树可能有多个,但边的权值之和总是唯一且最小的
  2. 最小生成树的边数等于顶点数 − 1 - 1 1,删掉一条边则不连通,增加一条边则会出现回路
  3. 如果一个连通图本身就是一棵树,则其最小生成树就是它本身
  4. 只有连通图才有生成树,非连通图只有生成森林

Prim 算法(普利姆)

从某一个顶点开始构建生成树,每次将代价最小的新顶点纳入生成树,直到所有顶点都纳入为止

在这里插入图片描述

时间复杂度为 O ( ∣ V ∣ 2 ) O(|V|^2) O(V2),适合用于边稠密图

Kruskal 算法(克鲁斯卡尔)

每次选择一条权值最小的边,使这条边的两头连通(原本已经连通的就不选),直到所有结点都连通

时间复杂度为 O ( ∣ E ∣ l o g 2 ∣ E ∣ ) O(|E|log_2|E|) O(Elog2E),适合用于边稀疏图

最短路径

在这里插入图片描述

“G港” 是个物流集散中心,经常需要往各个城市运送东西,怎么运送距离最近? —— 单源最短路径问题

各个城市之间也需要互相往来,相互之间怎么走距离最近? —— 每对顶点间的最短路径

BFS 求无权图的单源最短路径

在这里插入图片描述

无权图可以视为一种特殊的带权图,只是每条边的权值都为 1 1 1

我们对广度优先遍历的代码稍微改改,就能得到最短路径的 B F S BFS BFS 算法

//求顶点 u 到其他顶点的最短路径
void BFS_MIN_Distance(Graph G, int u) {
	//d[i] 表示从 u 到 i 结点的最短路径
	for (int i = 0; i < G.vexnum; ++i) {
		d[i] = 0;			//初始化最短路径长度
		path[i] = -1;		//最短路径是从哪个顶点过来的
	}
	
	d[u] = 0;
	visited[u] = true;
	EnQueue(Q, u);
	while (!isEmpty(Q)) {				//BFS算法主过程
		DeQueue(Q, u);					//队头元素 u 出队
		for (w = FirstNeighbor(G, u); w >= 0; w = NextNeighbor(G, u, w)) {
			if (!visited[w]) {			//w 为 u 的尚未访问的邻接顶点
				d[w] = d[u] + 1;		//路径长度加 1
				path[w] = u;			//最短路径为从 u 到 w
				visited[w] = true;		//设置已访问标记
				EnQueue(Q, w);			//顶点 w 入队
			}//if
		}//for
	}//while
}

如果我们从 2 2 2 这个顶点对图进行广度优先遍历,那么得到的广度优先生成树一定是以 2 2 2 为根的、高度最小的生成树

B F S BFS BFS 算法的局限性 —— 求单源最短路径只适用于无权图,或者所有边的权值都相同的图

Dijkstra 算法

带权路径长度 —— 当图是带权图时,一条路径上所有边的权值之和,称为该路径的带权路径长度

在这里插入图片描述

我们需要 3 3 3 个数组:

  • f i n a l final final 数组:标记各顶点是否已经找到最短路径
  • d i s t dist dist 数组:顶点的最短路径长度
  • p a t h path path 数组:路径上的前驱顶点

初始:若从 V 0 V_0 V0 开始,令 f i n a l [ 0 ] = t r u e ; d i s t [ 0 ] = 0 ; p a t h [ 0 ] = − 1 final[0] = true; dist[0] = 0; path[0] = -1 final[0]=true;dist[0]=0;path[0]=1,其余顶点 f i n a l [ k ] = f a l s e ; d i s t [ k ] = a r c s [ 0 ] [ k ] ; p a t h [ k ] = ( a r c s [ 0 ] [ k ] = = ∞ )   ? − 1 : 0 final[k] = false; dist[k] = arcs[0][k]; path[k] = (arcs[0][k] == \infty) \ ? -1 : 0 final[k]=false;dist[k]=arcs[0][k];path[k]=(arcs[0][k]==) ?1:0

后面的 n − 1 n - 1 n1 轮处理:循环遍历所有顶点,找到还没有确定最短路径,且 d i s t dist dist 最小的顶点 V i V_i Vi, 令 f i n a l [ i ] = t r u e final[i] = true final[i]=true。并检查所有邻接自 V i V_i Vi 的顶点 V j V_j Vj,若 f i n a l [ j ] = f a l s e final[j] = false final[j]=false d i s t [ i ] + a r c s [ i ] [ j ] < d i s t [ j ] dist[i] + arcs[i][j] < dist[j] dist[i]+arcs[i][j]<dist[j],则令 d i s t [ j ] = d i s t [ i ] + a r c s [ i ] [ j ] ;   p a t h [ j ] = i dist[j] = dist[i] + arcs[i][j]; \ path[j] = i dist[j]=dist[i]+arcs[i][j]; path[j]=i a r c s [ i ] [ j ] arcs[i][j] arcs[i][j] 表示 V i V_i Vi V j V_j Vj 的弧的权值)

时间复杂度为 O ( N 2 − N ) O(N^2 - N) O(N2N),简化后为 O ( N 2 ) O(N^2) O(N2)(其中 N N N 为顶点个数),在这个过程中,每一轮处理我们都需要循环遍历所有顶点,找到还没有确定最短路径,且 d i s t dist dist 最小的顶点 V i V_i Vi,这一步需要 O ( N ) O(N) O(N) 的时间,因为有 N N N 个点,然后有 n − 1 n - 1 n1 处理,相乘即为此算法的时间复杂度

注意:Dijkstra 算法不适用于有负权值的带权图

Floyd 算法

F l o y d Floyd Floyd 算法:求出每一对顶点之间的最短路径

使用动态规划思想,将问题的求解分为多个阶段

对于 n n n 个顶点的图 G G G,求任意一对顶点 V i V_i Vi -> V j V_j Vj 之间的最短路径可分为如下几个阶段:

  • 初始:不允许在其他顶点中转,最短路径是?
  • 0:若允许在 V 0 V_0 V0 中转,最短路径是?
  • 1:若允许在 V 0 、 V 1 V_0、V_1 V0V1 中转,最短路径是?
  • 2:若允许在 V 0 、 V 1 、 V 2 V_0、V_1、V_2 V0V1V2 中转,最短路径是?
  • n - 1:若允许在 V 0 、 V 1 、 V 2 、 . . . 、 V n − 1 V_0、V_1、V_2、... 、V_{n- 1} V0V1V2...Vn1 中转,最短路径是?

假设有如下这个图,要我们求出每一对顶点之间的最短路径

在这里插入图片描述

我们一步步来分析这个问题

初始状态,不允许在其他顶点中转,其最短路径(也就是图的邻接矩阵)为

在这里插入图片描述

每两个顶点之间的中转点为( − 1 -1 1 表示无中转点)

在这里插入图片描述

接着,下一步,若允许在 V 0 V_0 V0 中转,最短路径是什么呢?

对此,我们需要进行下列比较:

  • A ( k − 1 ) [ i ] [ j ] > A ( k − 1 ) [ i ] [ k ] + A ( k − 1 ) [ k ] [ j ] A^{(k-1)}[i][j] > A^{(k-1)}[i][k] + A^{(k-1)}[k][j] A(k1)[i][j]>A(k1)[i][k]+A(k1)[k][j],则 A ( k ) [ i ] [ j ] = A ( k − 1 ) [ i ] [ k ] + A ( k − 1 ) [ k ] [ j ] ; A^{(k)}[i][j] = A^{(k-1)}[i][k] + A^{(k-1)}[k][j]; A(k)[i][j]=A(k1)[i][k]+A(k1)[k][j];   p a t h ( k ) [ i ] [ j ] = k \ path^{(k)}[i][j] = k  path(k)[i][j]=k,否则, A ( k ) A^{(k)} A(k) A ( k − 1 ) A^{(k - 1)} A(k1) 保持原值

在前面的 A ( − 1 ) A^{(-1)} A(1) 图中,只有求 V 2 V_2 V2 V 1 V_1 V1 的最短路径时符合比较的要求:

  • A ( − 1 ) [ 2 ] [ 1 ] > A ( − 1 ) [ 2 ] [ 0 ] + A ( − 1 ) [ 0 ] [ 1 ] = 11 A^{(-1)}[2][1] > A^{(-1)}[2][0] + A^{(-1)}[0][1] = 11 A(1)[2][1]>A(1)[2][0]+A(1)[0][1]=11
  • 所以 A ( 0 ) [ 2 ] [ 1 ] = 11 ,   p a t h ( 0 ) [ 2 ] [ 1 ] = 0 A^{(0)}[2][1] = 11, \ path^{(0)}[2][1] = 0 A(0)[2][1]=11, path(0)[2][1]=0

对应的最短路径和中转点图为:

在这里插入图片描述

3 3 3 步,若允许在 V 0 、 V 1 V_0、V_1 V0V1 中转,最短路径是?

在这一步,只有求 V 0 V_0 V0 V 2 V_2 V2 的最短路径时符合比较的要求:

  • A ( 0 ) [ 0 ] [ 2 ] > A ( 0 ) [ 0 ] [ 1 ] + A ( 0 ) [ 1 ] [ 2 ] = 10 A^{(0)}[0][2] > A^{(0)}[0][1] + A^{(0)}[1][2] = 10 A(0)[0][2]>A(0)[0][1]+A(0)[1][2]=10
  • 所以 A ( 1 ) [ 0 ] [ 2 ] = 10 ,   p a t h ( 1 ) [ 0 ] [ 2 ] = 1 A^{(1)}[0][2] = 10, \ path^{(1)}[0][2] = 1 A(1)[0][2]=10, path(1)[0][2]=1

对应的最短路径和中转点图为:

在这里插入图片描述

4 4 4 步,若允许在 V 0 、 V 1 、 V 2 V_0、V_1、V_2 V0V1V2 中转,最短路径是?

在这一步,只有求 V 1 V_1 V1 V 0 V_0 V0 的最短路径时符合比较的要求:

  • A ( 1 ) [ 1 ] [ 0 ] > A ( 1 ) [ 1 ] [ 2 ] + A ( 1 ) [ 2 ] [ 0 ] = 9 A^{(1)}[1][0] > A^{(1)}[1][2] + A^{(1)}[2][0] = 9 A(1)[1][0]>A(1)[1][2]+A(1)[2][0]=9
  • 所以 A ( 2 ) [ 1 ] [ 0 ] = 9 ,   p a t h ( 2 ) [ 1 ] [ 0 ] = 2 A^{(2)}[1][0] = 9, \ path^{(2)}[1][0] = 2 A(2)[1][0]=9, path(2)[1][0]=2

对应的最短路径和中转点图为:

在这里插入图片描述

A ( − 1 ) A^{(-1)} A(1) p a t h ( − 1 ) path^{(-1)} path(1) 开始,经过 n n n 轮递推( n n n 为顶点个数),得到了 A ( n − 1 ) A^{(n-1)} A(n1) p a t h ( n − 1 ) path^{(n-1)} path(n1)

核心代码如下

//前期准备工作,根据图的信息初始化矩阵 A 和 path

//每一步比较
for (int k = 0; k < n; ++k) {						//考虑以 Vk 为中转点
	for (int i = 0; i < n; ++i) {					//遍历整个矩阵,i 为行号,j 为列号
		for (int j = 0; j < n; ++j) { 
			if (A[i][j] > A[i][k] + A[k][j]) {
				A[i][j] = A[i][k] + A[k][j];		//更新最短路径长度
				path[i][j] = k;						//更新中转点
			}
		}
	}
}

时间复杂度为 O ( ∣ V ∣ 3 ) O(|V|^3) O(V3),空间复杂度为 O ( ∣ V ∣ 2 ) O(|V|^2) O(V2)

注意:

  • F l o y d Floyd Floyd 算法可以用于负权值带权图
  • F l o y d Floyd Floyd 算法不能解决带有 “负权回路” 的图(有负权值的边组成回路),这种图有可能没有最短路径,如下图

在这里插入图片描述

总结

对比方面BFS 算法Dijkstra 算法Floyd 算法
无权图
带权图
带负权值的图
带负权回路的图
时间复杂度 O ( ∣ V ∣ 2 ) O(|V|^2) O(V2) O ( ∣ V ∣ + ∣ E ∣ ) O(|V| + |E|) O(V+E) O ( ∣ V ∣ 2 ) O(|V|^2) O(V2) O ( ∣ V ∣ 3 ) O(|V|^3) O(V3)
通常用于求无权图的单源在最短路径求带权图的单源最短路径求带权图中各顶点间的最短路径

也可以用 D i j k s t r a Dijkstra Dijkstra 算法求所有顶点间的最短路径,重复 ∣ V ∣ |V| V 次即可,总的时间复杂度也为 O ( ∣ V ∣ 3 ) O(|V|^3) O(V3)

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

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

相关文章

棋盘覆盖问题(Java)

文章目录棋盘覆盖问题&#xff08;Java&#xff09;1、问题描述2、算法设计思路3、代码实现4、复杂度分析5、参考棋盘覆盖问题&#xff08;Java&#xff09; 1、问题描述 在一个2k2k个方格组成的棋盘中,若恰有一个方格与其他方格不同,则称该方格为一特殊方格,且称该棋盘为一个…

D. Radio Towers(斐波那契+逆元)

Problem - 1452D - Codeforces 在一条坐标线上有n2个城镇&#xff0c;编号从0到n1。第i个城镇位于第i点。 你在1,2,......,n个镇上各建一座无线电塔&#xff0c;概率为12&#xff08;这些事件是独立的&#xff09;。之后&#xff0c;你想把每个塔的信号功率设置为1到n的某个整…

OpenGL 透明度

目录 一.OpenGL 透明度 1.IOS Object-C 版本1.Windows OpenGL ES 版本2.Windows OpenGL 版本 二.OpenGL 透明度 GLSL Shader三.猜你喜欢 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 >> OpenGL ES 基础 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 &…

轻松使用TomCat、Maven和Servlet

文章目录TomcatTomcat下载启动Tomcat启动Tomcat失败的原因使用TomcatMaven创建Maven项目Maven依赖管理Servlet1.创建Maven项目2.引入依赖3.构建目录结构4.编写Servlet代码5.程序打包6.程序部署7.验证程序使用IDEA上Tomcat插件简化步骤5和步骤6Tomcat Tomcat 就是基于 Java 实现…

单点登录等功能该用 Keycloak 这种开源框架实现吗?

Keycloak 是一个开源软件产品&#xff0c;旨在为现代的应用程序和服务&#xff0c;提供包含身份管理和访问管理功能的单点登录工具。 开源软件虽然能够定制和修改源代码&#xff0c;还可以降低开发成本&#xff0c;但是 Keycloak 实现起来还是有不少问题&#xff1a; 用户迁移…

python实现五子棋游戏(pygame版)(附零基础学习资料)

前言 使用python实现pygame版的五子棋游戏&#xff1b; 环境&#xff1a;Windows系统python3.8.0 &#xff08;文末送读者福利&#xff09; 游戏规则&#xff1a; 1、分两位棋手对战&#xff0c;默认黑棋先下&#xff1b;当在棋盘点击左键&#xff0c;即在该位置绘制黑棋&a…

APT 攻击溯源方法

概述&#xff1a; 当今世界正值百年未有之大变局&#xff0c;网络空间成为继陆、海、空、天之后的第五大疆域&#xff0c;安全威胁也随之延伸至网络空间。没有网络安全就没有国家安全&#xff0c;在新时代网络空间安全已经上升至国家安全的高度。高级持续性威胁(Advanced Pers…

yolov1模型

目录 一、机器视觉算法 二、yolov1 预测阶段&#xff08;向前推断&#xff09;​ 三、预测阶段的后处理 &#xff08;声明&#xff1a;本文章是在学习他人视频的学习笔记&#xff0c;图片出处均来自该up主&#xff0c;侵权删 视频链接&#xff1a;为什么要学YOLOV1_哔哩哔哩_b…

拿铁DHT-PHEV座舱智能程度体验笔记(超详细)

评测时间&#xff1a; •第一次 2022年10月1日-10月7日 •第二次 2022年10月25日 评测配置&#xff1a; •两驱超大杯 18.98万元好评功能盘点 座舱芯片及内存&#xff1a;高通骁龙 8155&#xff0c;算力8TOPS&#xff0c;存储8GB&#xff0c;内存12G&#xff0c;一流的配置。 四…

领悟《信号与系统》之 连续时间信号的时域分析法

连续时间信号的时域分析法一、LTI 连续系统的响应1. LTI 微分方程的建立与求解2. LTI 连续系统的零输入响应与零状态响应1. 零输入响应2. 零状态响应3. 全响应二、冲激响应和阶跃响应1. 冲激响应2. 阶跃响应三、卷积积分及其性质1. 任意信号的分解2. 任意信号作用下的零状态响应…

一个合格的中级前端工程师需要掌握的 28 个 JavaScript 技巧

1. 判断对象的数据类型 使用 Object.prototype.toString 配合闭包&#xff0c;通过传入不同的判断类型来返回不同的判断函数&#xff0c;一行代码&#xff0c;简洁优雅灵活&#xff08;注意传入 type 参数时首字母大写&#xff09; 不推荐将这个函数用来检测可能会产生包装类型…

【跨境电商】6种实用有效的策略帮助改善客户沟通

关键词&#xff1a;跨境电商卖家、客户沟通 1.什么是客户沟通&#xff1f; 客户沟通是公司与消费者的互动。品牌识别接触点并通过各种渠道&#xff08;例如电话、电子邮件和实时聊天&#xff09;在每个接触点建立关系。公司可以通过始终如一的参与并将消费者置于这种互动的中心…

【Redis】内存回收:内存淘汰策略

【Redis】内存回收&#xff1a;内存淘汰策略 文章目录【Redis】内存回收&#xff1a;内存淘汰策略一、Redis内存回收-过期key处理二、Redis内存回收-内存淘汰策略一、Redis内存回收-过期key处理 如果你发现&#xff0c;平时在操作 Redis 时&#xff0c;并没有延迟很大的情况发生…

Watermelon Book(二)线性模型

文章目录线性回归对数几率回归线性类别分类多分类学习类别不平衡问题基本形式&#xff1a;若给定 d个属性描述的示例x(x1,x2,x3…xd)&#xff0c;则线性模型试图学得一个 通过属性的线性组合来进行预测。f(x)W1*X1W2*X2...Wn*Xnw(T)xbw(w1;w2;w3;wn;)线性模型形式简单、易于建模…

[附源码]java毕业设计校园共享单车系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

排序算法——七种排序算法汇总,详细

文章目录排序排序的概念及应用一、直接插入排序1. 简介2.动图展示3.过程4.代码5.总结二、希尔排序1.简介2.过程3.代码4.总结三、选择排序1.简介2.代码3.总结四、堆排序1.代码2.总结五、冒泡排序1.过程2.代码3.总结六、快速排序1.简介2.过程3.两种优化快速排序的思想4.代码-递归…

【附源码】计算机毕业设计JAVA学生校内兼职管理平台

【附源码】计算机毕业设计JAVA学生校内兼职管理平台 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JAVA…

什么是 SSH 密钥? 生成、身份验证、密钥对信息等

SSH 密钥不仅可以提高安全性&#xff0c;还可以实现当今企业所需的大规模连接流程、单点登录 (SSO) 以及身份和访问管理的自动化。 什么是 SSH 密钥&#xff1f; SSH 密钥是安全外壳 (SSH) 协议中使用的安全访问凭证。 SSH 密钥使用基于公钥基础设施 (PKI) 技术&#xff08;数…

Android12窗口模糊(二)高斯模糊API源码解析

前言 在 Android 12 中&#xff0c;提供了一些用于实现窗口模糊处理效果&#xff08;例如背景模糊处理和模糊处理后方屏幕&#xff09;的公共 API。窗口模糊处理或跨窗口模糊处理用于模糊处理给定窗口后方的屏幕。 有两种窗口模糊处理方式&#xff0c;可用于实现不同的视觉效果…

不小心清空了回收站怎么恢复,回收站删除的东西可以恢复吗

不小心清空了回收站怎么恢复&#xff1f;回收站是操作系统提供的一个非常实用的功能&#xff0c;专门为用户保存从电脑硬盘删除的各种数据&#xff0c;因而很多时候我们都会用到回收站&#xff0c;它能够保存各种数据&#xff0c;我们也能够在里面恢复自己想要的数据&#xff0…