圖的單源最短路徑(Dijkstra演算法)

卡巴拉的樹發表於2017-12-19

在許多路由問題中,尋找圖中一個頂點到另一個頂點的最短路徑或最小帶權路徑是非常重要的提煉過程。正式表述為,給定一個帶權有向圖G = (V, E) , 頂點sv中頂點t的最短路徑為在邊集E中連線st代價最小的路徑。要做到這一點首先要解決更為一般的單源最短路徑問題。在單源最短路徑問題中,計算從一個起始頂點s到其他與之相鄰頂點之間的最短路勁。

Dijkstra演算法

解決單源最短路徑問題的方法之一就是Dijkstra演算法。Dijkstra演算法會生成一顆最短路徑樹,樹的根為起始頂點s, 樹的分支為從頂點s到圖G中所有其他頂點的最短路徑。此演算法要求圖中的所有權值均為非負數。與Prim演算法類似,Dijkstra演算法也採用貪心演算法,它總是將當前看起來最近的最短的邊加入最短路徑中。

從根本上來說,Dijkstra演算法通過選擇一個頂點,並不斷探測與之相關的邊,類似廣度優先搜尋,找出當前距離最近的點。

演算法流程:

1. 求從頂點`a`開始的單源最短路徑,就是圖中每個點距離`a`的最短路。

  1. 求從頂點a開始的單源最短路徑,就是圖中每個點距離a的最短路。

2. 選定`a`,標記訪問過了,首先初始化圖中各點與`a`的距離,在實際程式碼中一般用一個陣列`dist[i]`存放這個值,如果暫時不可達,存一個極大值在裡面。如圖,只有`b`,`c` 直接與`a`連線,這時候`dist[b]=8`,`dist[c]=4`。其它點的`dist[i]=NaN,`後面的運算就是不斷更新這個`dist`陣列。

  1. 選定a,標記訪問過了,首先初始化圖中各點與a的距離,在實際程式碼中一般用一個陣列dist[i]存放這個值,如果暫時不可達,存一個極大值在裡面。如圖,只有b,c 直接與a連線,這時候dist[b]=8,dist[c]=4。其它點的dist[i]=NaN,後面的運算就是不斷更新這個dist陣列。

3. 再選出`dist`最小的元素擴充套件,很明顯是`c`,標記`visit`,這時候通過`c`點,`f`,`e`也產生一個新的與`a`的距離,這時候更新`dist`陣列,他們之前與a的距離都是`NaN`,當然只要原來與`a`的距離大於通過`c`與`a`的距離,都需要更新。

  1. 再選出dist最小的元素擴充套件,很明顯是c,標記visit,這時候通過c點,fe也產生一個新的與a的距離,這時候更新dist陣列,他們之前與a的距離都是NaN,當然只要原來與a的距離大於通過ca的距離,都需要更新。

4. 再找出非`visit`中`dist`最小的點,找到`f`,因為`b, d, e`都與`f`相鄰,這時候比較通過`f`後與`a`的距離,如果比原來`dist`短,就更新`dist`。

  1. 再找出非visitdist最小的點,找到f,因為b, d, e都與f相鄰,這時候比較通過f後與a的距離,如果比原來dist短,就更新dist

5. 選擇頂點`b`。

  1. 選擇頂點b

6. 在選擇頂點`d, e`後形成最短路徑。

  1. 在選擇頂點d, e後形成最短路徑。

Dijkstra演算法實現:

 1  function Dijkstra(Graph, source):
 2
 3      create vertex set Q
 4
 5      for each vertex v in Graph:             // Initialization
 6          dist[v] ← INFINITY                  // Unknown distance from source to v
 7          prev[v] ← UNDEFINED                 // Previous node in optimal path from source
 8          add v to Q                          // All nodes initially in Q (unvisited nodes)
 9
10      dist[source] ← 0                        // Distance from source to source
11      
12      while Q is not empty:
13          u ← vertex in Q with min dist[u]    // Source node will be selected first
14          remove u from Q 
15          
16          for each neighbor v of u:           // where v is still in Q.
17              alt ← dist[u] + length(u, v)
18              if alt < dist[v]:               // A shorter path to v has been found
19                  dist[v] ← alt 
20                  prev[v] ← u 
21
22      return dist[], prev[]

複製程式碼

相關文章