最短路之Dijkstra(15张图解)

news/2024/5/10 6:15:36/文章来源:https://blog.csdn.net/csdner250/article/details/128897744

🌼多年后再见你 - 乔洋/周林枫 - 单曲 - 网易云音乐 闲来无事听听歌

Dijkstra可解决“单源最短路径”问题 

四种最短路算法

Floyd算法

时间复杂度高,但实现容易(5行核心代码),解决负权,适用于数据范围小

Dijkstra算法

不能解决负权边,但具有良好扩展性,且复杂度较低

Bellman-Ford / 队列优化Bellman-Ford

可解决负权边,且复杂度较低

本节学习指定一个点(源点)到其他顶点的最短路径(单源最短路径

比如下图,求1号顶点到2,3,4,5,6号顶点的最短路径  

与Floyd-Warshall一样,我们依然采用二维数组e存储顶点和边的关系,初始值如下图:

还需要一个一维数组dis(tant)来存储1号顶点到其他顶点的初始路程,如下图:

我们将此时dis数组中的值称为最短路程的“估计值” 

第一步:找确定值 (1)

先找离源点(1号)最近的顶点,由dis数组可知,2号最近,选择2号顶点后,dis[2]的值就从“估计值”变成了“确定值”(表示1号到2号的最短路程已确定)

敲重点!

下面的推理是Dijkstra算法的核心, ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

为什么确定了呢?因为:

1,离源点(1号顶点)最近的是2号顶点

2,这个图所有边都是正数

所以,通过其他顶点中转,使1号先经其他顶点,再到2号顶点的路程,肯定更长

所以此时dis[2]就是1号到2号最短路程的确定值

↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ 

第二步:从刚被确定的顶点“出边”

第一步确定了一个确定值,第二步我们从这个被确定的点,进行“出边”,有2->3, 2->4两条边

先判断 dis[2] + e[2][3] < dis[3],即判断能否借2号中转,使1号到3号的路程缩短,由下图可知,dis[2] + e[2][3] == 1 + 9等于10,dis[3] == 12,可以缩短,所以dis[3]更新为10

这个过程有个专业术语叫“松弛” ,即1号顶点到3号顶点的路程dis[3],通过2->3这条边“松弛”成功,这便是Dijkstra算法的主要思想

通过“边”来松弛1号顶点到其他顶点的路程

同理,判断dis[2] + e[2][4] < dis[4],dis[2] + e[2][4] == 1 + 3等于4,dis[4] == ∞

4 < ∞,所以dis[4]更新为4

 

围绕确定点2的出边结束,开始下一轮找确定点

第一步:找确定值 (2)

剩下未确定的3,4,5,6号顶点,选出离1号最近的点,通过上面更新后的dis数组,当前最近的是4号顶点,所以dis[4]从估计值变成确定值 

为什么此时dis[4]就确定是1号到4号的最短路径了呢?因为dis数组更新后,假设存在经一个或几个点中转,路程比dis[4]小,首先经2号中转后离1号顶点最近的点已确定,就是4号,所以不存在经2号中转比dis[4]小的

至于经3,5,6中转比dis[4]小,更不存在了,此时1到3,5,6不经中转都比dis[4]大

所以更新后的dis[4]必然确定了

第二步:从刚被确定的顶点“出边”

从被确定的4号顶点出边,4->3, 4->5, 4->6,

dis[4] + e[4][3] < dis[3](8 < 10),dis[4] + e[4][5] < dis[5](17 < ∞),dis[4] + e[4][6] < dis[6](19<∞)

出边完毕后,看下图:

第一步:找确定值 (3)

再在剩下未确定的3, 5, 6中,找出离1号最近的,即dis中未确定中的最小值,8 < 17 < 19

所以dis[3]从估计值变为确定值 

第二步:从刚被确定的顶点“出边”

只能从3向5出边,3不和6直接相连(不能出边),只能3->5了,dis[3] + e[3][5] == 8 + 5 == 13

dis[5] == 17,  13 < 17,所以dis[5]更新为13

第一步:找确定值 (4)

从剩下的5,6号找离1号最近的顶点,是5号,dis[5]从估计值变成确定值

第二步:从刚被确定的顶点“出边”

dis[5] + e[5][6] < dis[6](17 < 19),dis[6]更新为17

第一步:找确定值 (5)

在剩下的6号中找离1号最近的,就他一个了,所以dis[6]从估计值变确定值 

第二步:从刚被确定的顶点“出边”

没有未确定的值,出边失败~   算法结束

最终 

这便是1号顶点到其他顶点的最短路径,至此,“单源最短路径”问题解决

思路 

每次找到离源点最近的点,以该点为中心对未确定的点进行扩展 

1, 

将所有顶点分为两部分,一部分已确定(确定值),一部分未确定(估计值)

已确定的顶点,用book数组标记为1,比如book[4] = 1 

2, 

将某一点到源点最短路径用dis数组保存;二维数组e中,i 到 j 无法到达用e[i][j] = ∞来表示,i 到 i 用e[i][i] = 0来表示 

完整代码 

#include<cstdio>
int main()
{int e[10][10], dis[10], book[10], i, j, n, m;int t1, t2, t3, u, v, Min;int inf = 1e8; //infinity(n.)无穷//读入n个顶点, m条边scanf("%d%d", &n, &m);//初始化for(i = 1; i <= n; ++i)for(j = 1; j <= n; ++j) {if(i == j) e[i][j] = 0;else e[i][j] = inf;}//读入边for(i = 1; i <= m; ++i) {scanf("%d%d%d", &t1, &t2, &t3);e[t1][t2] = t3;}//初始化dis数组, 表示源点1号到其他点初始路程for(i = 1; i <= n; ++i)dis[i] = e[1][i];//初始化book数组for(i = 1; i <= n; ++i)book[i] = 0;//Dijkstra算法核心//源点不用确定, 所以是n - 1次遍历for(i = 1; i <= n - 1; ++i) {Min = inf;for(j = 2; j <= n; ++j) { //从顶点2开始//找确定值(未确定中找最小值)if(book[j] == 0 && dis[j] < Min) {Min = dis[j];u = j;}}book[u] = 1; //顶点u已确定//从刚被确定的顶点出边for(v = 2; v <= n; ++v) //从顶点2开始if(e[u][v] < inf && dis[u] + e[u][v] < dis[v])//两点连通且可更新dis[v] = dis[u] +e[u][v];}for(int i = 1; i <= n; ++i)printf("%d ", dis[i]);return 0;
}

输入输出

6 9
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4
0 1 8 4 13 17

由上述代码,可知Dijkstra时间复杂度为O(n^2) 

每次找到离源点最近顶点的时间复杂度是O(n),这里我们可以用优化(下下个博客讲) 

使找最近顶点的复杂度从O(n) --> O(logn)

        另外对于边数m小于n^2的稀疏图来说(我们称m < n^2的图为稀疏图,m > n^2的图为稠密图)

        可以用邻接表来代替矩阵,使整个算法时间复杂度优化O((m + n) * logn),但稀疏图的最坏情况是m == n^2,此时 (m + n) * logn 比 n^2 还大

        当然大多数情况不会有那么多边 

下面这个是稠密图

 

总结

每次出边就要判断,判断dis[a] + e[a][c] < dis[c]成立,就要更新dis[c] = dis[a] + e[a][c]

源点 -> a -> c的路程  小于  源点 -> c的路程 ,其中dis[a]是确定值

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

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

相关文章

方法的定义与使用详解

我们常用创建一个class修饰的就是一个类 其中有一个main方法&#xff0c;是主要的启动方法 这里写目录标题我们正常修饰的方法是由返回值的&#xff0c;但是用void修饰的没有static的使用方法中形参和实参的使用值传递引用传递类跟对象的关系this构造器--构造方法这个&#xf…

uniapp+java/springboot实现微信小程序APIV3支付功能

微信小程序的支付跟H5的支付和APP支付流程不一样&#xff0c;本次只描述下小程序支付流程。 一.账号准备 1.微信小程序账号 文档&#xff1a;小程序申请 小程序支付需要先认证&#xff0c;如果你有已认证的公众号&#xff0c;也可以通过公众号免费注册认证小程序。 一般30…

自定义input[type=file]上传按钮样式的四种方案,你知道几种?

目录前言方案1 opacity: 0;实现方案2 display:none样式元素选择 &#xff1a;label样式元素选择&#xff1a;其他元素::file-selector-button兼容性用法&#x1f9e8;&#x1f9e8;&#x1f9e8; 大家好&#xff0c;我是搞前端的半夏 &#x1f9d1;&#xff0c;一个热爱写文的前…

二、Linux文件 - Open函数讲解实战

目录 1.Open函数讲解 2.open函数实战 2.1 man 1 ls 查询Shell命令 2.2 man 2 open 查看系统调用函数 2.3项目实战 1.Open函数讲解 高频使用的Linux系统调用&#xff1a;open write read close Linux自带的工具&#xff1a;man手册&#xff1a; man 1是普通的shell…

【树和二叉树】数据结构二叉树和树的概念认识

前言&#xff1a;在之前&#xff0c;我们已经把栈和队列的相关概念以及实现的方法进行了学习&#xff0c;今天我们将认识一个新的知识“树”&#xff01;&#xff01;&#xff01; 目录1.树概念及结构1.1树的概念1.2树的结构1.3树的相关概念1.4 树的表示1.5 树在实际中的运用&a…

全国青少年编程等级考试scratch二级真题2022年9月(含题库答题软件账号)

青少年编程等级考试scratch真题答题考试系统请点击电子学会-全国青少年编程等级考试真题Scratch一级&#xff08;2019年3月&#xff09;在线答题_程序猿下山的博客-CSDN博客_小航答题助手1.数列&#xff1a;1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;6&#xff0c;…

程序的编译与链接(C语言为例) #代码写好后到运行期间要经过怎样的过程呢?# 粗略版 #

编译与链接前言程序的环境程序的编译与链接写在最后前言 每当我们运行一段代码时&#xff0c;编译器都会自动的帮我们编译代码并将代码转换为一个二进制可执行文件&#xff08;.exe&#xff09;&#xff0c; 有了这个可执行文件&#xff0c;便可以执行我们写的程序了。那么编译…

基于风光储能和需求响应的微电网日前经济调度(Python代码实现)【1】

目录 1 概述 2 知识点及数学模型 3 算例实现 3.1算例介绍 3.2风光参与的模型求解 3.3 风光和储能参与的模型求解 3.5 风光储能和需求响应都参与模型求解 3.6 结果分析对比 4 Python代码及算例数据 1 概述 近年来&#xff0c;微电网、清洁能源等已成为全球关注的热点…

数智化转型赋能企业,端看低代码如何发展

随着大数据、云计算、区块链等新兴技术的广泛运用&#xff0c; 现代企业在生产经营中产生的大量数据与信息逐渐成为发展的核心资产。与传统生产要素一起共同创建新的经济范式&#xff0c; 标志着我国经济发展正式迈入数字经济时代。 数字经济的快速崛起促使产业升级不断加速&am…

ASEMI整流模块MDQ75-16封装,MDQ75-16大小

编辑-Z ASEMI整流模块MDQ75-16参数&#xff1a; 型号&#xff1a;MDQ75-16 最大重复峰值反向电压&#xff08;VRRM&#xff09;&#xff1a;1600V 最大RMS电桥输入电压&#xff08;VRMS&#xff09;&#xff1a;1700V 最大平均正向整流输出电流&#xff08;IF&#xff09;…

Java IO流 序列化流 ObjectOutputStream ObjectInputStream

Java IO流 打印流 PrintStream PrintWriter Java IO流 序列化流 ObjectOutputStream ObjectInputStream Java IO流 缓冲流 BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter Java IO流 字符流 目录拷贝 Java IO流 字符流 FileWriter Java IO流 字符流 …

Sentinel服务熔断和流控

简介Sentinel随着微服务的流行&#xff0c;服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件&#xff0c;主要以流量为切入点&#xff0c;从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。源…

Java基础学习笔记(二十)—— 多线程(2)

多线程1 线程池1.1 线程状态1.2 线程池基本原理1.3 创建线程池1.4 任务拒绝策略2 共享变量的问题与解决2.1 存在的问题2.2 Volatile解决2.3 synchronized解决3 原子性3.1 原子性的实现&#xff08;synchronized&#xff09;3.2 AtomicInteger3.3 悲观锁和乐观锁4 并发工具类4.1…

算法 | 动态规划 | 系列题目讲解(思路记录part.1)

文章目录字符串分割三角矩阵路径总数最小路径和字符串分割 问题描述 给定一个字符串和一个词典dict&#xff0c;确定s是否可以根据词典中的词分成 一个或多个单词。 比如&#xff0c;给定 s “leetcode” dict [“leet”, “code”] 返回true&#xff0c;因为"leetcode…

吾剑未尝不利,国内Azure平替,科大讯飞人工智能免费AI语音合成(TTS)服务Python3.10接入

微软Azure平台的语音合成(TTS)技术确实神乎其技&#xff0c;这一点在之前的一篇&#xff1a;含辞未吐,声若幽兰,史上最强免费人工智能AI语音合成TTS服务微软Azure(Python3.10接入)&#xff0c;已经做过详细介绍&#xff0c;然则Azure平台需要信用卡验证&#xff0c;有一定门槛&…

基于Apache Maven构建多模块项目

title: 基于Apache Maven构建多模块项目 date: 2022-04-10 00:00:00 tags: Apache Maven多模块 categories:Maven 介绍 多模块项目由管理一组子模块的聚合器 POM 来构建。在大多数情况下聚合器位于项目的根目录中&#xff0c;并且必须是 pom 类型的项目。子模块是常规的 Mave…

CNN网络:ResNet(四)

ResNet论文[https://arxiv.org/pdf/1512.03385.pdf]。RestNet网络结构ResNet在2015年被提出&#xff0c;在ImageNet比赛classification任务上获得第一名&#xff0c;因为它“简单与实用”并存&#xff0c;之后很多方法都建立在ResNet50或者ResNet101的基础上完成的&#xff0c;…

手机逻辑系统(2)---逻 辑 音 频 电 路

第二节 逻 辑 音 频 电 路 逻辑音频电路在手机电路中占有重要的地位,它是手机系统的心脏。 逻辑音频电路包含无线通信呼叫处理、音频处理、数字语音处理、射频逻辑接口电路、各种射频功能控制、电源管理和用户接口模组等。 任何一部手机的逻辑音频电路部分都包含以上的一些功能…

1.2.4存储结构-磁盘管理:磁盘优化分布存储、磁盘优化分布存储例题

1.2.4存储结构-磁盘管理&#xff1a;磁盘优化分布存储、磁盘优化分布存储例题磁盘优化分布存储磁盘优化分布存储 假设某磁盘的每个磁道划分成11个物理块&#xff0c;每块存放1个逻辑记录。逻辑记录R0&#xff0c;R1&#xff0c;…&#xff0c;R9&#xff0c;R10存放在同一个磁…

将U盘制作为启动盘

将U盘制作为启动盘 制作之前需要先保证U盘中没有重要的文件&#xff0c;因为制作时会将已有文件删除 1 安装制作软件【wePE】 ①官网选择对应PE版本下载安装 官网下载地址:http://www.wepe.com.cn IT天空的U盘装机助理&#xff1a;https://www.itiankong.net/thread-357573-1…