暑假,小哼準備去一些城市旅遊。有些城市之間有公路,有些城市之間則沒有,如下圖。為了節省經費以及方便計畫旅程,小哼希望在出發之前知道任意兩個城市之前的最短路程。
上圖中有4個城市8條公路,公路上的數字表示這條公路的長短。請注意這些公路是單向的。我們現在需要求任意兩個城市之間的最短路程,也就是求任意兩個點之間的最短路徑。這個問題這也被稱為「多源最短路徑」問題。 現在需要乙個資料結構來儲存圖的資訊,我們仍然可以用乙個4*4的矩陣(二維陣列e)來儲存。比如1號城市到2號城市的路程為2,則設e[1][2]的值為2。2號城市無法到達4號城市,則設定e[2][4]的值為∞。另外此處約定乙個城市自己是到自己的也是0,例如e[1][1]為0,具體如下。
現在回到問題:如何求任意兩點之間最短路徑呢?通過之前的學習我們知道通過深度或廣度優先搜尋可以求出兩點之間的最短路徑。所以進行n2遍深度或廣度優先搜尋,即對每兩個點都進行一次深度或廣度優先搜尋,便可以求得任意兩點之間的最短路徑。可是還有沒有別的方法呢? 我們來想一想,根據我們以往的經驗,如果要讓任意兩點(例如從頂點a點到頂點b)之間的路程變短,只能引入第三個點(頂點k),並通過這個頂點k中轉即a->k->b,才可能縮短原來從頂點a點到頂點b的路程。那麼這個中轉的頂點k是1~n中的哪個點呢?甚至有時候不只通過乙個點,而是經過兩個點或者更多點中轉會更短,即a->k1->k2b->或者a->k1->k2…->k->i…->b。比如上圖中從4號城市到3號城市(4->3)的路程e[4][3]原本是12。如果只通過1號城市中轉(4->1->3),路程將縮短為11(e[4][1]+e[1][3]=5+6=11)。其實1號城市到3號城市也可以通過2號城市中轉,使得1號到3號城市的路程縮短為5(e[1][2]+e[2][3]=2+3=5)。所以如果同時經過1號和2號兩個城市中轉的話,從4號城市到3號城市的路程會進一步縮短為10。通過這個的例子,我們發現每個頂點都有可能使得另外兩個頂點之間的路程變短。好,下面我們將這個問題一般化。
當任意兩點之間不允許經過第三個點時,這些城市之間最短路程就是初始路程,如下。
假如現在只允許經過1號頂點,求任意兩點之間的最短路程,應該如何求呢?只需判斷e[i][1]+e[1][j]是否比e[i][j]要小即可。e[i][j]表示的是從i號頂點到j號頂點之間的路程。e[i][1]+e[1][j]表示的是從i號頂點先到1號頂點,再從1號頂點到j號頂點的路程之和。其中i是1~n迴圈,j也是1~n迴圈,**實現如下。
for(i=1;i<=n;i++)
}在只允許經過1號頂點的情況下,任意兩點之間的最短路程更新為:
通過上圖我們發現:在只通過1號頂點中轉的情況下,3號頂點到2號頂點(e[3][2])、4號頂點到2號頂點(e[4][2])以及4號頂點到3號頂點(e[4][3])的路程都變短了。 接下來繼續求在只允許經過1和2號兩個頂點的情況下任意兩點之間的最短路程。如何做呢?我們需要在只允許經過1號頂點時任意兩點的最短路程的結果下,再判斷如果經過2號頂點是否可以使得i號頂點到j號頂點之間的路程變得更短。即判斷e[i][2]+e[2][j]是否比e[i][j]要小,**實現為如下。
在只允許經過1和2號頂點的情況下,任意兩點之間的最短路程更新為:
通過上圖得知,在相比只允許通過1號頂點進行中轉的情況下,這裡允許通過1和2號頂點進行中轉,使得e[1][3]和e[4][3]的路程變得更短了。
同理,繼續在只允許經過1、2和3號頂點進行中轉的情況下,求任意兩點之間的最短路程。任意兩點之間的最短路程更新為:
最後允許通過所有頂點作為中轉,任意兩點之間最終的最短路程為:
整個演算法過程雖然說起來很麻煩,但是**實現卻非常簡單,核心**只有五行:
這段**的基本思想就是:最開始只允許經過1號頂點進行中轉,接下來只允許經過1和2號頂點進行中轉……允許經過1~n號所有頂點進行中轉,求任意兩點之間的最短路程。用一句話概括就是:從i號頂點到j號頂點只經過前k號點的最短路程。
另外需要注意的是:floyd-warshall演算法不能解決帶有「負權迴路」(或者叫「負權環」)的圖,因為帶有「負權迴路」的圖沒有最短路。例如下面這個圖就不存在1號頂點到3號頂點的最短路徑。因為1->2->3->1->2->3->…->1->2->3這樣路徑中,每繞一次1->-2>3這樣的環,最短路就會減少1,永遠找不到最短路。其實如果乙個圖中帶有「負權迴路」那麼這個圖則沒有最短路。
弗洛伊德演算法
弗洛伊德演算法 floyd 又稱為是插點法。目的是求加權圖中頂點中最短路徑的方法。本文通過舉例子的方法想你具體解釋何為弗洛伊德演算法。有乙個送禮物的問題,是csdn上的乙個題目,題目的詳情是這樣的。hehe和xixi在乙個地方玩遊戲,xixi把n 1件禮物 hehe以前送給xixi的 分別藏在了另外...
弗洛伊德演算法
floyd演算法詳解 求解任意兩點間的最短距離 floyd warshall演算法,簡稱floyd演算法,用於求解任意兩點間的最短距離,時間複雜度為o n 3 我們平時所見的floyd演算法的一般形式如下 1void floyd 注意下第6行這個地方,如果dist i k 或者dist k j 不存...
弗洛伊德演算法
弗洛伊德演算法 求任意一點i到任意一點j的最短路。分析 求i到j的最短路,大可以使用群舉法,因為點都是離散的,i到j的路徑是有限的,所以一定可以通過群舉法得到最短路,但群舉法卻沒太大意義,他的意義在於 把群舉法 通過修改 進行分類,得到好的演算法。flod演算法的分類標準是 通過i到j過點的情況進行...