【算法】弗洛伊德(Floyd)算法


這個算法主要要弄懂三個循環的順序關系。

弗洛伊德(Floyd)算法過程:
1、用D[v][w]記錄每一對頂點的最短距離。
2、依次掃描每一個點,並以其為基點再遍歷所有每一對頂點D[][]的值,看看是否可用過該基點讓這對頂點間的距離更小。

算法理解:

最短距離有三種情況:
1、兩點的直達距離最短。(如下圖<v,x>)
2、兩點間只通過一個中間點而距離最短。(圖<v,u>)
3、兩點間用通過兩各以上的頂點而距離最短。(圖<v,w>)
對於第一種情況:在初始化的時候就已經找出來了且以后也不會更改到。
對於第二種情況:弗洛伊德算法的基本操作就是對於每一對頂點,遍歷所有其它頂點,看看可否通過這一個頂點讓這對頂點距離更短,也就是遍歷了圖中所有的三角形(算法中對同一個三角形掃描了九次,原則上只用掃描三次即可,但要加入判斷,效率更低)。
對於第三種情況:如下圖的五邊形,可先找一點(比如x,使<v,u>=2),就變成了四邊形問題,再找一點(比如y,使<u,w& gt;=2),可變成三角形問題了(v,u,w),也就變成第二種情況了,由此對於n邊形也可以一步步轉化成四邊形三角形問題。(這里面不用擔心哪個點要先找哪個點要后找,因為找了任一個點都可以使其變成(n-1)邊形的問題)。

結合代碼 並參照上圖所示 我們來模擬執行下 這樣才能加深理解:
第一關鍵步驟:當k執行到x,i=v,j=u時,計算出v到u的最短路徑要通過x,此時v、u聯通了。
第二關鍵步驟:當k執行到u,i=v,j=y,此時計算出v到y的最短路徑的最短路徑為v到u,再到y(此時v到u的最短路徑上一步我們已經計算過來,直接利用上步結果)。
第三關鍵步驟:當k執行到y時,i=v,j=w,此時計算出最短路徑為v到y(此時v到y的最短路徑長在第二步我們已經計算出來了),再從y到w。

依次掃描每一點(k),並以該點作為中介點,計算出通過k點的其他任意兩點(i,j)的最短距離,這就是floyd算法的精髓!同時也解釋了為什么k點這個中介點要放在最外層循環的原因.

對於這個算法,網上有一個證明的版本:

floyd算法是一個經典的動態規划算法。用通俗的語言來描述的話,首先我們的目標是尋找從點i到點j的最短路徑。從動態規划的角度看問題,我們需要為這個目標重新做一個詮釋(這個詮釋正是動態規划最富創造力的精華所在),floyd算法加入了這個概念  Ak(i,j):表示從i到j中途不經過索引比k大的點的最短路徑。

    這個限制的重要之處在於,它將最短路徑的概念做了限制,使得該限制有機會滿足迭代關系,這個迭代關系就在於研究:假設Ak(i,j)已知,是否可以借此推導出Ak-1(i,j)。

    假設我現在要得到Ak(i,j),而此時Ak(i,j)已知,那么我可以分兩種情況來看待問題:1. Ak(i,j)沿途經過點k;2. Ak(i,j)不經過點k。如果經過點k,那么很顯然,Ak(i,j) = Ak-1(i,k) + Ak-1(k,j),為什么是Ak-1呢?因為對(i,k)和(k,j),由於k本身就是源點(或者說終點),加上我們求的是Ak(i,j),所以滿足不經過比k大的點的條件限制,且已經不會經過點k,故得出了Ak-1這個值。那么遇到第二種情況,Ak(i,j)不經過點k時,由於沒有經過點k,所以根據概念,可以得出Ak(i,j)=Ak-1(i,j)。現在,我們確信有且只有這兩種情況---不是經過點k,就是不經過點k,沒有第三種情況了,條件很完整,那么是選擇哪一個呢?很簡單,求的是最短路徑,當然是哪個最短,求取哪個,故得出式子:

    Ak(i,j) = min( Ak-1(i,j), Ak-1(i,k) + Ak-1(k,j) )

    現在已經得出了Ak(i,j) = Ak-1(i,k) + Ak-1(k,j) 這個遞歸式,但顯然該遞歸還沒有一個出口,也就是說,必須定義一個初始狀態,事實上,這個初始狀態取決於索引k是從0開始還是從1開始,上面的代碼是C寫的,是以0為開始索引,但一般描述算法似乎習慣用1做開始索引,如果是以1為開始索引,那么初始狀態值應設置為A0了,A0(i,j)的含義不難理解,即從i到j的邊的距離。也就是說,A0(i,j) = cost(i,j) 。由於存在i到j不存在邊的情況,也就是說,在這種情況下,cost(i,j)無限大,故A0(i,j) = oo(當i到j無邊時)

    到這里,已經列出了求取Ak(i,j)的整個算法了,但是,最終的目標是求dist(i,j),即i到j的最短路徑,如何把Ak(i,j)轉換為dist(i,j)?這個其實很簡單,當k=n(n表示索引的個數)的時候,即是說,An(i,j)=dist(i,j)。那是因為當k已經最大時,已經不存在索引比k大的點了,那這時候的An(i,j)其實就已經是i到j的最短路徑了。

    從floyd算法中不難看出,要設計一個好的動態規划算法,首先需要研究是否能把目標進行重新詮釋(這一步是最關鍵最富創造力的一步),轉化為一個可以被分解的子目標,如果可以轉化,就要想辦法尋找數學等式使目標收斂為子目標,如果這一步可以實現了,還需要研究該遞歸收斂式的出口,即初始狀態是否明確(這一步往往已經簡單了)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM