1. 程式人生 > >最短路演算法(Floyd、Dijkstra)

最短路演算法(Floyd、Dijkstra)

         本節學習指定一個點(源點)到其餘各個頂點的最短路徑,也叫做“單源最短路徑”。例如下圖中的1號頂點到2、3、4、5、6號頂點的最短路徑。
    
    與Floyd演算法一樣,這裡仍然使用二維陣列g來儲存頂點之間邊的關係,初始值如下:
    
    我們還需要用一個一維陣列dis來儲存1號頂點到其餘各頂點的初始路程,如下:
    
    我們將此時dis陣列中的值稱為最短路程的“估計值”。
    既然求1號頂點到其餘各個頂點的最短路程,那就先找一個離1號頂點最近的頂點。通過陣列dis可知離1號頂點最近的是2號頂點。當選擇了2號頂點後,dis[2]的值就已經從“估計值”變成了“確定值”,即1號頂點到2號頂點的最短路程就是當前dis[2]的值。為什麼呀?因為目前離1號頂點最近的是2號頂點,並且這個圖所有的邊都是正數,那麼肯定不可能通過第三個頂點中轉,使得1號頂點到2號頂點的路程進一步縮短了。因為1號頂點到其他頂點的路程肯定沒有1號到2號頂點短。
    既然選擇了2號頂點,接下來再來看2號頂點有哪些出邊。有2->3和2->4這兩條邊。先討論通過2->3這條邊能否讓1號到3號頂點的路程變短,也就是說現在來比較dis[3]和dis[2]+g[2][3]的大小。其中dis[3]表示1號頂點到3號頂點的路程,dis[2]表示1號頂點到2號頂點的路程,g[2][3]表示2->3這條邊。所以dis[2]+g[2][3]就表示從1號頂點先到2號頂點,再通過2->3這條邊,到達3號頂點的路程。
    我們發現dis[3]=12,dis[2]+g[2][3]=1+9=10,dis[3]>dis[2]+g[2][3],因此dis[3]要更新為10。這個過程稱為“鬆弛
”,1號頂點到3號頂點的路程即dis[3],通過2->3這條邊鬆弛成功。這便是Dijkstra演算法的主要思想:通過“邊”來鬆弛1號頂點到其餘各個頂點的路程。
    同理,通過2->4(g[2][4]),可以將dis[4]的值從∞鬆弛為4(dis[4]初始為∞,dis[2]+g[2][4]=1+3=4,dis[4]>dis[2]+g[2][4],因此dis[4]要更新為4)。
    剛才我們對2號頂點所有的出邊進行了鬆弛。鬆弛完畢後dis陣列為:
    
     接下來,繼續在剩下的3、4、5和6號頂點中,選出離1號頂點最近的頂點。通過上面更新過的dis陣列,當前離1號頂點最近的是4號頂點。此時,dis[4]的值已經從“估計值”變為了“確定值”。下面繼續對4號頂點的所有出邊(4->3, 4->5和4-6)用剛才的方法進行鬆弛。鬆弛完畢後dis陣列為:
    

    繼續在剩下的3、5和6號頂點中,選出離1號頂點最近的頂點。這次選擇3號,對3號頂點的所有出邊(3->5)進行鬆弛。鬆弛完畢之後dis陣列為:
    
    繼續在剩下的5和6號頂點中,選出離1號頂點最近的頂點。這次選5號頂點。對5號頂點的所有出邊(5->4)進行鬆弛。鬆弛完畢之後dis陣列為:
    
    最後對6號頂點進行鬆弛。因為6號頂點沒有出邊,因此不用處理。最終dis陣列如下,這便是1號頂點到其餘各頂點的最短路徑。
    
    現在我們總結下演算法的基本思想。