Dijkstra


在大多数最短路径问题中,Dijkstra 算法是最常用、效率最高的。它是一种“单源”最短路径算法,一次计算能得到从一个起点 s 到其他所有点的最短距离长度、最短路径的途径点。

一、Dijkstra的算法思想

Dijkstra 的模型例如多米诺骨牌,你可以想象下面的场景:

在图中所有的边上,排满多米诺骨牌,相当于把骨牌看成图的边。一条边上的多米诺骨牌数量,和边的权值(例如长度或费用)成正比。规定所有骨牌倒下的速度都是一样的。如果在一个结点上推倒骨牌,会导致这个结点上的所有骨牌都往后面倒下去。

当我们在起点 s 推倒骨牌,可以观察到,从 s 开始,它连接的边上的骨牌都逐渐倒下,并到达所有能达到的结点。在某个结点 t ,可能先后从不同的线路倒骨牌过来;先倒过来的骨牌,其经过的路径,肯定就是从 s 到达 t 的最短路;后倒过来的骨牌,对确定结点 t 的最短路没有贡献,不用管它。从整体看,这是一个起点 s 扩散到整个图的过程。

而在这个过程中,观察所有结点的最短路径是这样得到的:

  1. 在 s 的所有直连邻居中,最近的邻居 u,骨牌首先到达。u 是第一个确定最短路径的结点。从 u 直连到 s 的路径肯定是最短的,因为如果 u 绕道别的结点到 s,必然更远。
  2. 把后面骨牌的倒下分成 2 部分,一部分是从 s 继续倒下到 s 的其它的直连邻居,另一部分从 u 出发倒下到 u 的直连邻居。那么下一个到达的结点 v,必然是 s 或者 u 的一个直连邻居。v 是第二个确定最短路径的结点。
  3. 继续以上步骤,在每一次迭代过程中,都能确定一个结点的最短路径。

我们用下面的表来总结 Dijkstra 算法的基本过程:

步骤 做法 具体操作 结果
1 从起点s出发,用BFS扩展它的邻居结点。 把这些邻居点放到一个集合A中,并记录这些点到s的距离。
2 选择距离s最近的那个邻居v,继续用BFS扩展v的邻居 (1)在A中找到距离s最小的点v,把v的邻居点,放到A中;
(2)如果v的邻居经过v中转,到s的距离更短,则更新这些邻居到s的距离;
(3)从集合A中移走v,后面不再处理v。
(1)得到了从s到v的最短路;
(2)v的邻居更新了到s的距离。
3 重复步骤2,直到所有点都扩展到并计算完毕 集合A为空。计算出了所有点到s的最短距离

Dijkstra算法应用了贪心法的思想,即“抄近路走,肯定能找到最短路径”。算法可以简单概况为:Dijkstra = BFS + 贪心。实际上,“Dijkstra + 优先队列 = BFS + 优先队列(队列中的数据是从起点到当前点的距离)”

我们来分析一下Dijkstra 的复杂度:设图的点有 n 个,边有 m 条。编码的时候,集合 A 一般用优先队列来模拟。优先队列可以用堆或其他高效的数据结构实现,往优先队列中插入一个数、取出最小值的操作都是 O(logn) 的。一共往队列中插入 m 次(每条边都要进集合 A 一次),取出 n 次(每次从集合 A 中取出距离 s 最短的一个点,取出时要更新这个点的所有邻居到 s 的距离,设一个点平均有 k 个邻居),那么总复杂度是 O(m×logn+n×k×logn) ≈ O(m×logn),一般有 m 大于 n。不过要注意,在稠密图情况下 m 是 O(n^2) ,k 是 O(n)的。在计算单源最短路时,Dijkstra 是效率最高的算法。

Dijkstra 存图使用的数据结构:题目若是稀疏图,往往 n 很大而 m 小,必须使用邻接表、链式前向星来存图;若是稠密图则 n 较小,就用简单的邻接矩阵,用邻接表也并不能减少存储空间。

Dijkstra 的高效稳定: 从集合 AA 中得到一个点的最短路后,继续 BFS 时只需要扩展和更新这个点的邻居,范围很小,算法是高效的;而每次从集合A中都能得到一个点的最短路,算法是稳定的。

但Dijkstra的边的权值不能为负数。因为 Dijkstra 基于BFS,计算过程是从起点 s 逐步往外扩散的过程,每扩散一次就用贪心得到到一个点的最短路。扩散要求路径越来越长,如果遇到一个负权边,会导致路径变短,使扩散失效。见下图,设当前得到 s→u 的最短路,路径长度为 8,此时 s→u 的路径计算已经结束了。继续扩展 u 的邻居,若 u 到邻居 v 的边权是 -15,而 v 到 s 的距离为 20,那么 u 存在另一条途径 v 到 s 的路径,距离为 20 + (-15) = 5,这推翻了前面已经得到的长度 8 的最短路,破坏了 BFS 的扩散过程。

二、Dijkstra的执行过程

编程的主要内容是维护两个集合:已确定最短路径的结点集合 A 、这些结点向外扩散的邻居结点集合 B。程序逻辑是:

  1. 把起点 s 放到 A 中,把 s 所有的邻居放到 B 中。此时,邻居到 s 的距离就是直连距离。
  2. 从 B 中找出距离起点 s 最短的结点 u,放到 A 中。
  3. 把 u 所有的新邻居放到 B 中。显然,u 的每一条边都连接了一个邻居,每个新邻居都要加进去。其中 u 的一个新邻居 v,它到 s 的距离 dis(s,v) 等于 dis(s, u) + dis(u, v)。
  4. 重复步骤 2、3,直到 B 为空时,结束。

计算结束后,就可以得到从起点 s 到其它所有点的最短距离啦。

举个栗子:如图,起点是 1,现在我们要求 1 到其它所有结点的最短路径。

步骤如下:

  1. 1 到自己的距离最短,把 1 放到集合 A 里:A={1}。把 1 的邻居放到集合 B里:B={(2-5), (3-2)}。其中 (2-5) 表示结点 2 到起点的距离是 5 。
  2. 从 B 中找到离集合 A 最近的结点,是结点 3。在 A 中加上 3,现在 A={1, 3},也就是说得到了从 1 到 3 的最短距离;从 B 中拿走 (3-2),现在 B={(2-5)}。
  3. 对结点 3 的每条边,扩展它的新邻居,放到 B 中。3 的新邻居是 2 和 4,那么 B={(2-5), (2-4), (4,7)}。其中 (2-4) 是指新邻居 2 通过 3 到起点 1,距离是 4。由于 (2-4) 比 (2-5)更好,丢弃 (2-5),B={(2-4), (4-7)}。
  4. 重复步骤 2、3。从 B 中找到离起点最近的结点,是结点 2。在 A 中加上 2,并从 B 中拿走 (2-4);扩展 2 的邻居放到 B 中。现在 A={1, 3, 2},B={(4-7), (4-5)}。由于 (4-5) 比 (4-7)更好,丢弃 (4-7),B={(4-5)}。
  5. 从 B 中找到离起点最近的结点,是结点 4。在 A 中加上 4,并从 B 中拿走(4-5)。已经没有新邻居可以扩展。现在 A={1, 3, 2, 4},B 为空,结束。

我们在看看这个过程的复杂度:

我们设图的边共有 m 个,需要往集合 B 中扩展 m 次。在每次扩展后,需要找集合 B 中距离起点最小的结点。集合 B 最多可能有 n 个结点。把问题抽象为:每次往集合 B 放一个数据;然后在 B 中的 n 个数中找最小值......

这个最小值要怎么找呢?

如果往 B 中放数据是乱放,找最小值也是用类似冒泡的简单方法,复杂度是 n,那么总复杂度是 O(nm),和 Bellman-Ford 一样。不过上述方法可以改进,得到更好的复杂度,改进方法是:

  1. 每次往 B 中放新数据时,按从小到大的顺序放,用二分法的思路,复杂度是 O(logn),保证最小的数总在最前面;
  2. 找最小值,直接取 B 的第一个数,复杂度是 O(1)。

这样 Dijkstra 算法总的复杂度就是 O(mlogn),是最高效的最短路算法。而我们在编程时,一般不用自己写上面的程序,直接用 STL 的优先队列就可完成数据的插入和提取。

三、Dijkstra经典题目练习


点击 -> Dijkstra经典题目分析及参考代码


王国

题目描述

小明是王国的王子,今天是他登基之日。在即将成为国王之前,老国王给他出了道题,他想要考验小明是否有能力管理国家。

题目的内容如下:

王国一共有 N 个建筑和 M 条单向道路,每条道路都连接着两个建筑,每个建筑都有自己编号,分别为 1∼N 。(其中皇宫的编号为 1)

国王想让小明回答从皇宫到每个建筑的最短路径是多少,但紧张的小明此时已经无法思考,请你编写程序帮助小明回答国王的考核。

输入描述

输入第一行包含三个正整数 N,M。

第 2 到 M + 1 行每行包含三个正整数 u,v,w,表示 uv 之间存在一条距离为 w 的路。

1 ≤ ≤ 3×10^5,1 ≤ ≤ 10^6,1 ≤ ui​,vi​ ≤ N,0 ≤ wi​ ≤ 10^9。

输出描述

输出仅一行,共 N 个数,分别表示从皇宫到编号为 1∼N 建筑的最短距离,两两之间用空格隔开。(如果无法到达则输出 -1)

样例输入

3 3
1 2 1
1 3 5
2 3 2

样例输出

0 1 3

如有错误和需要改进完善之处,欢迎大家纠正指教。

最短路算法——Dijkstra相关推荐

  1. spfa算法_10行实现最短路算法——Dijkstra

    今天是算法数据结构专题的第34篇文章,我们来继续聊聊最短路算法. 在上一篇文章当中我们讲解了bellman-ford算法和spfa算法,其中spfa算法是我个人比较常用的算法,比赛当中几乎没有用过其他 ...

  2. zuc算法代码详解_最短路算法-dijkstra代码与案例详解

    引言 在研究路径选择和流量分配等交通问题时,常常会用到最短路算法.用最短路算法解决交通问题存在两个难点: 一.算法的选择和程序的编写.最短路算法有很多种改进算法和启发式算法,这些算法的效率不同,适用的 ...

  3. 单源(多源)最短路算法Dijkstra、Bellman-Ford、SPFA

    最短路算法 单源最短路:即一个点到任意点的最短路径 多源最短路:即任意一点到任意一点的最短路径 Dijkstra算法: 这个算法是通过点去更新最短路,每次找离源点最近的一个顶点,然后以该顶点为中心进行 ...

  4. 指定起终点的最短路算法-Dijkstra标号法及其改进

    源代码来源于司守奎老师<数学建模与算法>,本人加了一些注释供大家参考: function [mydistance,mypath]=mydijkstra(a,sb,db); % 输入:a-邻 ...

  5. dijkstra算法matlab程序_编程习题课 | 用最短路算法为你的小地图导航

    简介:路网拓扑的正确导入方式,运筹学算法的完整实战案例,最详细的代码讲解与分享. 引言:在研究路径选择和流量分配等交通问题时,常常会用到最短路算法.用最短路算法解决交通问题存在两个难点:一.算法的选择 ...

  6. 坐在马桶上看算法:Dijkstra最短路算法

                                                             [坐在马桶上看算法]算法7:Dijkstra最短路算法 上周我们介绍了神奇的只有五行的 ...

  7. Dijkstra 最短路算法(只能计算出一条最短路径,所有路径用dfs)

    上周我们介绍了神奇的只有五行的 Floyd 最短路算法,它可以方便的求得任意两点的最短路径,这称为"多源最短路".本周来来介绍指定一个点(源点)到其余各个顶点的最短路径,也叫做&q ...

  8. 详解最短路算法模板(dijkstra+floyd+spfa)

    1.Floyd_Warshall算法 核心思路:d[i][j] = min{d[i][j], d[i][k] + d[k][j]} 从i到j有两种路径,经过k点或是不经过k点,所以我们枚举k即可求所有 ...

  9. 图的最短路算法(Dijkstra和Floyd-Warshall)

    一.单源最短路(Dijkstra算法) 基本思想 选定一个源点,按路径长度递增次序,逐步产生最短路径(贪心),直到此源点到其他各顶点的最短路径全部求出为止. 数据结构 带权有向图G=(V,E),V = ...

  10. HDU2544 最短路【Dijkstra算法】

    最短路 Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submis ...

最新文章

  1. premiere pr 波纹编辑 滚动编辑 比率拉伸 工具使用
  2. Spring Boot 打成war包部署到tomcat8.5.20报无法访问
  3. GDCM:rle转img文件的测试程序
  4. html设计一张试卷算分,HTML试卷10班分享[共5页].doc
  5. 华硕vm510l拆电池图解_图解说设备:凯斯CX80C你会买吗?
  6. angular 点击事件阻止冒泡及默认行为
  7. python中分支结构包括哪些_python中的分支结构
  8. Android开发在路上:少去踩坑,多走捷径
  9. 浅析如何通过PHP类的反射来实现依赖注入
  10. JQuery在循环中绑定事件的问题详解
  11. 再见2006,奋斗2007
  12. php array sum 小数位,多维数组上的PHP Array_Sum
  13. 电脑常见故障排除手册(黑屏、死机、重启、蓝屏)
  14. UVA - 10129 Play on Words(欧拉回路)
  15. 数据加密技术之加密算法
  16. 解决iOS app集成共享QQ场地,微信的朋友,朋友等功能圈,不能采用苹果公司的审计问题...
  17. python机器学习——文本情感分析(英文文本情感分析)
  18. mobi文件怎么转化为PDF
  19. 开源项目: FlycoTabLayout SlidingTabLayout不显示字体的问题
  20. 2级c语言题库及答案,2019-C语言二级考试题库(含答案)

热门文章

  1. 手写数字图像识别-SVM算法投票法实现多分类
  2. gps坐标转成火星坐标
  3. 【力扣面试】面试题 04.02. 最小高度树(就是创建二叉平衡树)
  4. 由PPP项目总结的几点项目经验
  5. 腾讯云服务器申请自助退款流程(图文教程)
  6. svn和git版本管理
  7. 图像检索代码python_图像检索系列——利用深度学习实现以图搜图
  8. HTML中怎么点击超链接让新页面在另一个窗口打开?
  9. kuka机器人程序是c语言吗,KUKA机器人示教器编程问题讲解——KUKA机器人
  10. PHP公文签报源码,基于PHP企业公文流转系统.docx