1. 程式人生 > >Floyd演算法與動態規劃

Floyd演算法與動態規劃

轉載:http://blog.csdn.net/zh___zh/article/details/40476201

PS:本文是在他人博文基礎上加以修改而來,將從 Ak(i,j) 推導 Ak-1(i,j) 改為從 Ak-1(i,j) 推導 Ak(i,j),為的是符合自己的思維習慣,更好的理解floyd算法,並且方便以後檢視。

在此首先對原作者表示感謝!

下面進入正文

    floyd的程式碼實現其實很簡單:    


  1. void floyd()  

  2. {  

  3.     for(k=0;k<n;k++)  

  4.         for(i=0;i<n;i++)  

  5.             for(j=0;j<n;j++)  

  6.                 A[i][j]=min(A[i][j],A[i][k]+A[k][j]);  

  7. }  

    floyd演算法是一個經典的動態規劃演算法,目標是尋找從點i到點j(圖中任意兩點)的最短路徑。從動態規劃的角度看問題,我們需要為這個目標重新做一個詮釋(這個詮釋正是動態規劃最富創造力的精華所在)。假設圖有n個頂點,依次為0,1,,n-1floyd演算法加入了這個概念

    Ak(i,j):表示從頂點i到頂點j且中間頂點的序號不大於K的最短路徑

    這個限制的重要之處在於,它將最短路徑的概念做了限制,使得該限制有機會滿足迭代關係,這個迭代關係就在於研究:假設Ak-1(i,j)已知,是否可以藉此推匯出Ak(i,j)。針對此問題,採用數學歸納法,我們分兩步解決:

   1、由Ak(i,j)的定義可得初始狀態(即中間不經過其他任何頂點):A-1(i,j) = cost(i,j)。(cost(i,j)為連線頂點i 和頂點j 的邊的權值,若兩頂點間無邊,則值為無窮大)

    2、假設此時Ak-1(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呢?因為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)的整個演算法了,但是,最終的目標是求dist(i,j),即i到j的最短路徑,如何把Ak(i,j)轉換為dist(i,j)?這個其實很簡單,當k=n-1(n表示圖中頂點的個數)的時候,即是說,An-1(i,j)=dist(i,j)。那是因為當k已經最大時,已經不存在索引比k大的點了,那這時候的An-1(i,j)其實就已經是頂點i 到頂點j 的最短路徑了。

    從動態規劃演算法設計的角度來講,求解決策過程的最優化問題,首先應將待求解問題分解成若干個子問題,確定待求解問題與子問題的定量關係,先求解子問題,然後從這些子問題的解得到原問題的解。本文可看做求解定量關係部分(即由子問題出發,求解原問題)。


    個人總結:劃分的過程是從上往下,求解的過程是從下往上。