引言:
DAG上的最短路可以用dp解得,容易得到状态转移方程。但如果图中可以有环,就要使用其他算法了。这里先考虑边权均为正的最短路问题。
Contents:
一、 普通的dijkatra实现 O(n2)
三、 基于优先队列的Dijkstra O(mlogn)
给出样例问题(图片引自Tanky Woo):
对下图中的有向图,用Dijkstra算法计算从任意源顶点到其它顶点间最短路径。
输入:
6
7
1 2 10
1 4 30
1 5 100
2 3 50
3 5 10
4 3 20
4 5 60
1
2
3
4
5
输出:
No.1->No.5 :60
No.2->No.5 :60
No.3->No.5 :10
No.4->No.5 :30
No.5->No.5 :0
接下来就此问题,分别介绍几种复杂度不同的实现方法。
首先来谈谈这个算法。记st为起点,dist[i]为结点 i 到st的最短路径长。
初始化dist[st] = 0; 其余dist为INF(类似maxint)。当前结点 u = st。
从当前点u出发遍历邻点,更新dist[v] = min{ dist[v], dist[u]+w[u][v]}; ----------这里有点像状态转移
设一个集合S,总是把当前不在S中的结点的最小dist对应的点加入S中。
当所有点都在集合S中时,完毕。此时dist数组更新完毕,即从st到图上任意结点的最短路长都已经算出。
理解:关键在于集合S,每次取当前最小的dist。可见取到S中的点的dist都是已经更新完毕的了,即已算出的。
可以用反证明法想想,如果某次dist[i]是最小的dist,但是st到 i 还存在经过 u' 的更短的路,则
dist[u']必然 小于dist[i],即u'会比 i 先成为当前点,那时dist[i]就会在u'作为当期点的时候被更新为
dist[u']+w[u'][i]了。 所以,dist[i]必是st到 i 的最短路长。
每次取一个元素到S中,所以循环n-1次,每次循环时,求最小dist(遍历n个结点)和更新相邻dist值(若采用邻接矩阵)都是O(n)的,所以时间复杂度为O(n^2)。
这里附上其他说法