1. 程式人生 > >從最短路徑角度證明floyd演算法正確性

從最短路徑角度證明floyd演算法正確性

       floyd最短路徑演算法是用於求圖中任意兩點之間最短路徑的經典演算法,但是關於其正確性的證明書上以及網上並沒有很好的解釋。一年前自己從最短路徑結果本身出發想出了證明辦法,但是一直沒有發表,今天和朋友又聊起了這個話題,就整理了思路,寫出來,與大家分享。

       我們這裡從有N個節點的無向圖入手進行證明。若圖中兩個節點不連通,那麼經過演算法計算後仍為不連通。若它們連通就必然存在一條最短路徑。假設任意2節點之間存在一條最短路徑,該路徑上有M個節點(M<N)。floyd演算法為三重迴圈,我們重點考慮最外層迴圈,我們將最外層迴圈此時所在的節點稱為“橋點”。橋點遍歷到了某一節點時,演算法就會計算任意一點A到橋點的距離加上任意一點B到橋點距離的和,並將這個和與矩陣中儲存的A到B的路徑的距離進行比較,將短的存入矩陣中相應的位置。可以根據以下程式碼進行理解。


下面是證明用到的圖


       為了敘述方便,我們假設固定兩節點分別為A和B,它們之間最短路徑的節點為中間部分的12個節點,因為橋點會遍歷完圖中的N的節點,因此必然會遍歷A、B以及中間的12個節點。

       假設橋點遍歷到了s5節點,則由floyd演算法我們必然會有計算s4-s5加上s5-s6的過程,而且這個計算結果會儲存到矩陣裡,因為最短路徑上任意一段都是最短路徑,因此它的計算結果必然被儲存,我們也就知道了s4-s5-s6這段路徑的距離。這裡將s4和s6分別稱為“橋沿節點”,s5成為“橋頂節點”。這樣我們就知道了2個橋沿節點經過橋頂節點之後的路徑距離,而且這個距離還是它們之間的最短路徑距離。

       我下面就要證明這個橋會變大,而且不同的橋會連線,最終會變成一個大橋,這個大橋的兩個邊沿節點就是A和B。首先橋頂都是被橋點遍歷過的節點,不會再被遍歷(下面會說明),所以下面橋點只會遍歷橋沿節點或者其它節點。若遍歷的橋沿節點,則橋會擴大,如s9擴充套件為s8-s9,若不是橋沿節點就會產生新的橋頂節點和新的橋。若一個橋的橋頂節點都被遍歷過了那麼橋點遍歷橋沿節點時,它會變大,但是橋頂節點還是都被遍歷過了。若2個橋的橋沿節點為同一幾點,那麼橋點遍歷到這個節點時就會將2個橋合為一個橋。如圖中s3和s5被s4和成s3-s4-s5,若2個橋的橋頂節點都被遍歷過了,那麼由橋點連線起來的新的大橋的所有的橋頂節點也都是被遍歷過的。

        OK,所有的橋在產生時都只有一個橋頂節點,而且橋頂節點被橋點遍歷過了,這些初始橋的橋頂節點都被遍歷過,它們的擴充套件方式只有橋邊節點被橋點遍歷,或者與其它的橋合併,這樣產生的新的大橋的橋頂節點也都是被遍歷過的。以此類推,所有的橋頂節點都已經被橋點遍歷過,下面橋點只會遍歷橋沿節點擴充套件橋,或者其它節點產生新的橋,因為橋點會遍歷N個節點,因此會遍歷完中間路徑上的每一個節點,因此實際運算時會產生橋,然後橋點遍歷橋頂節點之外的節點來產生新的橋,或者擴充橋,最後,這些橋不斷擴大,導致橋沿節點重合,橋點可定會遍歷橋沿節點,因此橋會合並,最終出現一個橋沿節點為A和B的大橋,這時我們也就知道了A和B之間最短路徑的距離。

        因為A和B為任意節點,所以任何2個節點之間最短路徑上的節點被橋點遍歷完,都可以求得它們之間的最短路徑。因為橋點會遍歷完N個節點,所以任意連通的2個節點之間的最短路徑上的節點都會被遍歷到,所以我們也就會在計算過程中計算出過最短路徑距離,記住,我們每計算一個都會將計算結果與矩陣中的數值進行比較,將小的存入矩陣,所以這個過程中我們會在計算出最短路徑後將它填入矩陣。注意:這個最短路徑如果存在就一定會在某次計算得到其結果。

       有向圖一樣的,因為計算過程中會兩個方向都計算以此。比如橋點遍歷到s5時,s4-s5加上s5-s6會計算一次,s6-s5加上s5-s4還會計算一次,因此有向圖同樣適用。