在网络中,求两个不同顶点之间的所有路径 中,边的权值之和最小的那一条路径
- 这条路径就是两点之间的最短路径(Shortest Path)
- 第一个顶点为源点(Source)
- 最后一个顶点为终点(Destination)
单源最短路径(single-source shortest paths)
给定带权图 G = <V,E>,其中每条边 (vi,vj ) 上的权 W[vi,vj ] 是一个 非负实数 。计算从任给的一个源点 s 到所有其他顶点的最短路径
无权图的单源最短路算法
按照递增(非递减)的顺序找出到各个顶 点的最短路(BFS)
James Bond 从孤岛跳上岸,最少需要跳多少步?
void
dist[W] = S到W的最短距离
dist[S] = 0
path[W] = S到W的路上经过的某顶点
有权图的单源最短路算法
按照递增的顺序找出到各个顶点的最短路(Dijkstra算法)
Dijkstra算法基本思想
把所有结点分成两组
第一组 U 包括已确定最短路径的结点
第二组T= V–U 包括尚未确定最短路径的结点
按最短路径长度递增的顺序逐把第二组的结点加到第一组中 ,
直至从 源点
Dijkstra 算法
令U={源点
然后不断从集合T中选取到顶点
算法过程
(1) 引进一个辅助向量Dist,它的每个分量
Dist[j]表示的就是从
对任一未收录的顶点v,定义dist[v]为
若路径是按照递增(非递减)的顺序生成的,则
- 真正的最短路必须只经过U中的顶点(为什么?)
- 每次从未收录的顶点中选一个dist最小的收录(贪心)
- 增加一个v进入U,可能影响另外一个w的dist值!
dist[w] = min{dist[w], dist[v] + <v,w>的权重}
1、初始U={
2、从顶点
3、求次短路径的方法。
例如,当U={
算法描述:
(1)假设用带权的邻接矩阵ed 来表示带权有向图
(2)选择
Dist[j]:从
(3)修改从
Dijkstra单源最短路径迭代过程
Dijkstra单源最短路径算法
class
void
方法1:直接扫描所有未收录顶点
方法2:将dist存在最小堆中
更新dist[w]的值
Dijkstra算法时间代价分析
每次改变D[i].length
不删除,添加一个新值(更小的),作为堆中新元素。旧值被找到时,该结点一定被标记 为VISITED,从而被忽略
在最差情况下,它将使堆中元素数目由
Dijkstra算法
是否支持
- 有向图、无向图
- 非连通
- 有回路的图
- 权值为负
如果不支持
- 则修改方案?
针对有向图 (且“有源”)
- 若输入无向图?
- 照样能够处理 (边都双向)
对非连通图,有不可达
- 没有必要修改
支持回路
支持负权值?
Dijkstra算法不支持负权值
如果存在总权值为负的回路,则将出现权 值为
如果不存在负权回路呢?
Dijkstra算法不受负权边的影响吗?
即使不存在负的回路,也可能有在后面出现的负权值, 从而导致整体计算错误
主要原因是 Dijkstra 算法是贪心法,当作最小取进来后,不会返回去重新计算
持负权值的最短路径算法
• Bellman-Ford 算法
• 参考书 MIT “Introduction to Algorithms”
• SPFA 算法
多源最短路径问题:
求任意两顶点间的最短路径
方法1:直接将单源最短路算法调用|V|遍
方法2:
每对结点间的最短路径
• 还能用 Dijkstra 算法吗?
• 以每个结点为起点,调用 n 次 Dijkstra 算法
void
多源最短路算法
Floyd 算法
- 或者k
最短路径{},则=
- 或者k
最短路径{},则该路径必定由两段最短路径组成:
Floyd算法求每对结点之间的最短路径
用相邻矩阵 adj 来表示带权有向图
基本思想:
初始化
在矩阵
其中经过第k次迭代,
动态规划法
最短路径组合情况分析
由于第
一种是中间不经过结点
另中间经过结点
用弗洛伊德算法求下图所示的带权有向图G的每一对顶点间的最短路径及路径长度的过程如下。由矩阵path可知任何一对顶点间最短路径经过结点。
图 10:当任意两点之间不允许经过第三个点时,这些点之间最短路程就是初始路程:adj矩阵,最短路径经过结点是path矩阵。
只允许经过
图 11:只允许经过
图 12:只允许经过
void
python:
import