Dijkstra最短路演算法

2021-08-24 17:39:21 字數 2710 閱讀 5714

上週我們介紹了神奇的只有五行的floyd最短路演算法,它可以方便的求得任意兩點的最短路徑,這稱為「多源最短路」。本週來來介紹指定乙個點(源點)到其餘各個頂點的最短路徑,也叫做「單源最短路徑」。例如求下圖中的1號頂點到2、3、4、5、6號頂點的最短路徑。

與floyd-warshall演算法一樣這裡仍然使用二維陣列e來儲存頂點之間邊的關係,初始值如下。

我們還需要用乙個一維陣列dis來儲存1號頂點到其餘各個頂點的初始路程,如下。

我們將此時dis陣列中的值稱為最短路的「估計值」。

既然是求1號頂點到其餘各個頂點的最短路程,那就先找乙個離1號頂點最近的頂點。通過陣列dis可知當前離1號頂點最近是2號頂點。當選擇了2號頂點後,dis[2]的值就已經從「估計值」變為了「確定值」,即1號頂點到2號頂點的最短路程就是當前dis[2]值。為什麼呢?你想啊,目前離1號頂點最近的是2號頂點,並且這個圖所有的邊都是正數,那麼肯定不可能通過第三個頂點中轉,使得1號頂點到2號頂點的路程進一步縮短了。因為1號頂點到其它頂點的路程肯定沒有1號到2號頂點短,對吧o(∩_∩)o~

既然選了2號頂點,接下來再來看2號頂點有哪些出邊呢。有2->3和2->4這兩條邊。先討論通過2->3這條邊能否讓1號頂點到3號頂點的路程變短。也就是說現在來比較dis[3]和dis[2]+e[2][3]的大小。其中dis[3]表示1號頂點到3號頂點的路程。dis[2]+e[2][3]中dis[2]表示1號頂點到2號頂點的路程,e[2][3]表示2->3這條邊。所以dis[2]+e[2][3]就表示從1號頂點先到2號頂點,再通過2->3這條邊,到達3號頂點的路程。

我們發現dis[3]=12,dis[2]+e[2][3]=1+9=10,dis[3]>dis[2]+e[2][3],因此dis[3]要更新為10。這個過程有個專業術語叫做「鬆弛」。即1號頂點到3號頂點的路程即dis[3],通過2->3這條邊鬆弛成功。這便是dijkstra演算法的主要思想:通過「邊」來鬆弛1號頂點到其餘各個頂點的路程。

同理通過2->4(e[2][4]),可以將dis[4]的值從∞鬆弛為4(dis[4]初始為∞,dis[2]+e[2][4]=1+3=4,dis[4]>dis[2]+e[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號頂點。此時,dis[3]的值已經從「估計值」變為了「確定值」。對3號頂點的所有出邊(3->5)進行鬆弛。鬆弛完畢之後dis陣列為:

繼續在剩下的5和6號頂點中,選出離1號頂點最近的頂點,這次選擇5號頂點。此時,dis[5]的值已經從「估計值」變為了「確定值」。對5號頂點的所有出邊(5->4)進行鬆弛。鬆弛完畢之後dis陣列為:

最後對6號頂點所有點出邊進行鬆弛。因為這個例子中6號頂點沒有出邊,因此不用處理。到此,dis陣列中所有的值都已經從「估計值」變為了「確定值」。

最終dis陣列如下,這便是1號頂點到其餘各個頂點的最短路徑。

ok,現在來總結一下剛才的演算法。演算法的基本思想是:每次找到離源點(上面例子的源點就是1號頂點)最近的乙個頂點,然後以該頂點為中心進行擴充套件,最終得到源點到其餘所有點的最短路徑。基本步驟如下:

完整的dijkstra演算法**如下:

#include int main()

//初始化dis陣列,這裡是1號頂點到其餘各個頂點的初始路程

for(i=1;i<=n;i++)

dis[i]=e[1][i];

//book陣列初始化

for(i=1;i<=n;i++)

book[i]=0;

book[1]=1;

//dijkstra演算法核心語句

for(i=1;i<=n-1;i++)}}

//輸出最終的結果

for(i=1;i<=n;i++)

printf("%d ",dis[i]);

getchar();

getchar();

return 0;

}

可以輸入以下資料進行驗證。第一行兩個整數n  m。n表示頂點個數(頂點編號為1~n),m表示邊的條數。接下來m行表示,每行有3個數x y z。表示頂點x到頂點y邊的權值為z。

6 9

1 2 1

1 3 12

2 3 9

2 4 3

3 5 5

4 3 4

4 5 13

4 6 15

5 6 4

執行結果是

0 1 8 4 13 17
通過上面的**我們可以看出,這個演算法的時間複雜度是o(n2)。其中每次找到離1號頂點最近的頂點的時間複雜度是o(n),這裡我們可以用「堆」(以後再說)來優化,使得這一部分的時間複雜度降低到o(logn)。另外對於邊數m少於n2的稀疏圖來說(我們把m遠小於n2的圖稱為稀疏圖,而m相對較大的圖稱為稠密圖),我們可以用鄰接表(這是個神馬東西?不要著急,下週再仔細講解)來代替鄰接矩陣,使得整個時間複雜度優化到o( (m+n)logn )。請注意!在最壞的情況下m就是n2,這樣的話mlogn要比n2還要大。但是大多數情況下並不會有那麼多邊,因此(m+n)logn要比n2小很多。

最短路 Dijkstra演算法

dijksitra演算法求最短路僅僅適用於不存在右邊是負權的情況 bellman ford演算法沒有這乙個限制 主要特點是從起點為中心向外層層擴充套件,直到擴充套件到終點為止。即乙個最短路路徑中經過的所有點這條路均是其最短路。反證法易證 dijkstra基本思路 找到最短距離已經確定的頂點,從它出發...

dijkstra最短路演算法

dijkstra演算法 1.定義概覽 dijkstra 迪傑斯特拉 演算法是典型的單源最短路徑演算法,用於計算乙個節點到其他所有節點的最短路徑。主要特點是以起始點為中心向外層層擴充套件,直到擴充套件到終點為止。dijkstra演算法是很有代表性的最短路徑演算法,在很多專業課程中都作為基本內容有詳細的...

最短路 Dijkstra演算法

這是一類求單源最短路的演算法,也就是求某乙個頂點到其他所有頂點的最短路。它是按照最短路徑遞增的順序來計算的。先說一下大體思路 將圖中的頂點分為兩個集合,s,v s。s儲存已經求出最短路徑的頂點,v s儲存未求出最短路的頂點。然後演算法就是不斷額的求出v s中頂點的最短路,然後把它加入s中,直到所有頂...