一、最短路徑問(wèn)題(shortest path problem)
最短路徑問(wèn)題是圖論研究中一個(gè)經(jīng)典算法問(wèn)題,旨在尋找圖中兩節(jié)點(diǎn)或單個(gè)節(jié)點(diǎn)到其他節(jié)點(diǎn)之間的最短路徑。根據(jù)問(wèn)題的不同,算法的具體形式包括:
- 確定起點(diǎn)的最短路徑問(wèn)題,即給定起始節(jié)點(diǎn),求該節(jié)點(diǎn)到其他剩余節(jié)點(diǎn)的最短路徑,適合使用Dijkstra算法;
- 確定終點(diǎn)的最短路徑問(wèn)題,即給定終點(diǎn),求其他節(jié)點(diǎn)到該終點(diǎn)的最短路徑。在無(wú)向圖中,該問(wèn)題與確定起點(diǎn)的問(wèn)題等價(jià);在有向圖中,問(wèn)題等價(jià)于把所有路徑方向反轉(zhuǎn)的確定起點(diǎn)的問(wèn)題;
- 確定起點(diǎn)終點(diǎn)的最短路徑問(wèn)題,即給定起點(diǎn)和終點(diǎn),求兩節(jié)點(diǎn)之間的最短路徑;
- 全局最短路徑問(wèn)題,即求圖中所有節(jié)點(diǎn)之間的最短路徑,適合使用Floyd-Warshall算法。
常用的最短路徑算法包括:Dijkstra算法,A算法,Bellman-Ford算法,SPFA算法(Bellman-Ford算法的改進(jìn)版本),F(xiàn)loyd-Warshall算法,Johnson算法以及Bi-direction BFS算法。本文將重點(diǎn)介紹Dijkstra算法的原理以及實(shí)現(xiàn)。
二、Dijkstra算法介紹
1. 算法概覽
Dijkstra算法,翻譯作戴克斯特拉算法或迪杰斯特拉算法,于1956年由荷蘭計(jì)算機(jī)科學(xué)家艾茲赫爾.戴克斯特拉提出,用于解決賦權(quán)有向圖的單源最短路徑問(wèn)題。所謂單源最短路徑問(wèn)題是指確定起點(diǎn),尋找該節(jié)點(diǎn)到圖中任意節(jié)點(diǎn)的最短路徑,算法可用于尋找兩個(gè)城市中的最短路徑或是解決著名的旅行商問(wèn)題。
問(wèn)題描述:在無(wú)向圖中,
為圖節(jié)點(diǎn)的集合,
為節(jié)點(diǎn)之間連線邊的集合。假設(shè)每條邊
的權(quán)重為
,找到由頂點(diǎn)
到其余各個(gè)節(jié)點(diǎn)的最短路徑(單源最短路徑)。
2. 算法描述
為帶權(quán)無(wú)向圖,圖中頂點(diǎn)
分為兩組,第一組為已求出最短路徑的頂點(diǎn)集合(用
表示)。初始時(shí)
只有源點(diǎn),當(dāng)求得一條最短路徑時(shí),便將新增頂點(diǎn)添加進(jìn)
,直到所有頂點(diǎn)加入
中,算法結(jié)束。第二組為未確定最短路徑頂點(diǎn)集合(用
表示),隨著
中頂點(diǎn)增加,
中頂點(diǎn)逐漸減少。
-
初始化:
只包含起點(diǎn)
,
包含
外的其他頂點(diǎn)。
中的距離為起點(diǎn)
到頂點(diǎn)的距離。若
與
相鄰,則
中頂點(diǎn)
距離為
的邊緣權(quán)重;若
與
不相鄰,則
的距離為
;
-
更新
和
:從
中選出距離值最小的頂點(diǎn)
,并將頂點(diǎn)
添加至
;同時(shí),從
中移除
;
-
更新
中頂點(diǎn)到起點(diǎn)
的距離:由于
中添加了
,利用
進(jìn)一步更新
到其他頂點(diǎn)的距離,存在
的可能性;
- 反復(fù)迭代:重復(fù)第二步和第三步,直到遍歷完所有節(jié)點(diǎn)。
3. 算法示例
以下圖為例,對(duì)Dijkstra算法的工作流程進(jìn)行演示(以頂點(diǎn)為起點(diǎn)):

注:
01)是已計(jì)算出最短路徑的頂點(diǎn)集合;
02)是未計(jì)算出最短路徑的頂點(diǎn)集合;
03)表示頂點(diǎn)
到頂點(diǎn)
的最短距離為3
第1步:選取頂點(diǎn)添加進(jìn)

第2步:選取頂點(diǎn)添加進(jìn)
,更新
中頂點(diǎn)最短距離

第3步:選取頂點(diǎn)添加進(jìn)
,更新
中頂點(diǎn)最短距離

第4步:選取頂點(diǎn)添加進(jìn)
,更新
中頂點(diǎn)最短距離

第5步:選取頂點(diǎn)添加進(jìn)
,更新
中頂點(diǎn)最短距離

第6步:選取頂點(diǎn)添加進(jìn)
,更新
中頂點(diǎn)最短距離

第7步:選取頂點(diǎn)添加進(jìn)
,更新
中頂點(diǎn)最短距離

三、Dijkstra算法的R及Python軟件實(shí)現(xiàn)
1. R實(shí)現(xiàn)Dijkstra算法:igraph包中shortest.paths函數(shù)
示例:node編號(hào)1-7分別代表A,B,C,D,E,F,G
require(igraph)
graph_matrix<-as.matrix(read.table(text=
"node x1 x2 x3 x4 x5 x6 x7
1 0 12 NA NA NA 16 14
2 12 0 10 NA NA 7 NA
3 NA 10 0 3 5 6 NA
4 NA NA 3 0 4 NA NA
5 NA NA 5 4 0 2 8
6 16 7 6 NA 2 0 9
7 14 NA NA NA 8 9 0
", header=T))
nms<-graph_matrix[,1]
mat<-graph_matrix[,-1]
colnames(mat)<-rownames(mat)<-nms
mat[is.na(mat)]<-0
# create graph from adjacency matrix
g <- graph.adjacency(mat, weighted=TRUE)
# Get all path distances
(s.paths <- shortest.paths(g, algorithm = "dijkstra"))
(s.paths <- shortest.paths(g,4, algorithm = "dijkstra"))
(s.paths <- shortest.paths(g, algorithm = "dijkstra"))輸出結(jié)果:
1 2 3 4 5 6 7
1 0 12 22 22 18 16 14
2 12 0 10 13 9 7 16
3 22 10 0 3 5 6 13
4 22 13 3 0 4 6 12
5 18 9 5 4 0 2 8
6 16 7 6 6 2 0 9
7 14 16 13 12 8 9 0
(s.paths <- shortest.paths(g,4, algorithm = "dijkstra"))輸出結(jié)果:
1 2 3 4 5 6 7
4 22 13 3 0 4 6 12
2. Python語(yǔ)言實(shí)現(xiàn)Dijkstra算法:networkx 模塊
示例:
from dijkstar import Graph, find_path
graph=Graph()
graph.add_edge(1,2,{'cost':12})
graph.add_edge(1,6,{'cost':16})
graph.add_edge(1,7,{'cost':14})
graph.add_edge(2,3,{'cost':10})
graph.add_edge(2,6,{'cost':7})
graph.add_edge(2,1,{'cost':12})
graph.add_edge(3,2,{'cost':10})
graph.add_edge(3,4,{'cost':3})
graph.add_edge(3,5,{'cost':5})
graph.add_edge(3,6,{'cost':6})
graph.add_edge(4,3,{'cost':3})
graph.add_edge(4,5,{'cost':4})
graph.add_edge(3,5,{'cost':5})
graph.add_edge(3,6,{'cost':6})
graph.add_edge(4,3,{'cost':3})
graph.add_edge(4,5,{'cost':4})
graph.add_edge(5,3,{'cost':5})
graph.add_edge(5,4,{'cost':4})
graph.add_edge(5,6,{'cost':2})
graph.add_edge(5,7,{'cost':8})
graph.add_edge(6,1,{'cost':16})
graph.add_edge(6,2,{'cost':7})
graph.add_edge(6,3,{'cost':6})
graph.add_edge(6,5,{'cost':2})
graph.add_edge(6,7,{'cost':9})
graph.add_edge(7,1,{'cost':14})
graph.add_edge(7,5,{'cost':8})
graph.add_edge(7,6,{'cost':9})
cost_func = lambda u, v, e, prev_e: e['cost']
find_path(graph, 4, 7, cost_func=cost_func)
找到D(4)到G(7)的最短路徑:
PathInfo(nodes=[4, 5, 7], edges=[{'cost': 4}, {'cost': 8}], costs=[4, 8], total_cost=12)
參考資料:
[1] 維基百科,最短路徑問(wèn)題:https://zh.wikipedia.org/wiki/%E6%9C%80%E7%9F%AD%E8%B7%AF%E9%97%AE%E9%A2%98;
[2]CSDN,Dijkstra算法原理:https://blog.csdn.net/yalishadaa/article/details/55827681;
[3]RDocumentation: https://www.rdocumentation.org/packages/RNeo4j/versions/1.6.4/topics/dijkstra;
[4]RDocumentation: https://www.rdocumentation.org/packages/igraph/versions/0.1.1/topics/shortest.paths;
[5]Pypi: https://pypi.org/project/Dijkstar/