最短路最基本算法———Floyd算法
關于floyd算法
一、floyd簡介
引自百度百科
在計算機科學中,Floyd-Warshall算法是一種在具有正或負邊緣權重(但沒有負周期)的加權圖中找到最短路徑的算法。算法的單個執行將找到所有頂點對之間的最短路徑的長度(加權)。 雖然它不返回路徑本身的細節,但是可以通過對算法的簡單修改來重建路徑。 該算法的版本也可用于查找關系R的傳遞閉包,或(與Schulze投票系統相關)在加權圖中所有頂點對之間的最寬路徑。
是不是覺得很高深?沒錯,這段介紹并沒有什么多大的用。
換而言之
floyd就是一種求最短路的算法,最基礎的算法
優點: 代碼簡短,易于理解,可用于負邊權,可求所有點之間的距離
缺點: 時間復雜度爆炸
實現思想
其實floyd是利用dp的思想實現的,不斷尋找中間點求最優解
枚舉起始點,中點和終點,利用中點不斷對不同的起點終點進行松弛操作,
更新任意兩點之間的最優子答案,最后得到最優解
核心代碼
for(int k=1;k<=n;k++)//枚舉中點 {for(int i=1;i<=n;i++)//枚舉起點 {for(int j=1;j<=n;j++)//枚舉終點 {if(i!=j&&i!=k&&j!=k) //三點不是相同的點時dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);//利用中點進行松弛操作}} }是不是很easy?
當然并不是
你是否發現,或者有疑問,floyd的操作,如何能保證能得到最優解,而不是被埋沒在次優解里,
或者說你疑問為什么最外層循環是枚舉k,因為這樣才能保證這個算法的正確性
還記得開始的介紹的實現思想么
沒錯,動態規劃
我們設dis[k][i][j]dis [ k ] [ i ] [ j ]dis[k][i][j] 表示iii和jjj之間可以通過編號為1…k的節點的最短路徑。
那么則dis[k][i][j]可以從dis[k?1][i][j]dis [ k ] [ i ] [ j ] 可以從dis [ k -1 ] [ i ] [ j ]dis[k][i][j]可以從dis[k?1][i][j]轉移來,表示iii到jjj不經過kkk這個節點。
也可以從dis[k?1][i][k]+dis[k?1][k][j]dis [ k - 1 ] [ i ] [ k ] + dis [ k - 1 ] [ k ] [ j ]dis[k?1][i][k]+dis[k?1][k][j] 轉移過來,表示經過k這個點。
意思即dis[k][i][j]=min(dis[k?1][i][j],dis[k?1][i][k]+dis[k?1][k][j])dis [ k ] [ i ] [ j ] = min ( dis [ k - 1 ] [ i ] [ j ] ,dis [ k - 1 ] [ i ] [ k ] +dis [ k - 1 ] [ k ] [ j ] )dis[k][i][j]=min(dis[k?1][i][j],dis[k?1][i][k]+dis[k?1][k][j])
然后我們能發現我們能dis的第一維k是可以省略的,因為k只和k-1有關(就和背包問題中0/1背包和完全背包的一維優化一個原理)
所以當前的dis[i][j]dis [ i ] [ j ]dis[i][j] 都應該是完成上一層動態規劃的,如果k不是在最外層,那么dis[i][j]dis [ i ] [ j ]dis[i][j] 就不是完成上一層動態規劃的后的狀態,有可能有的點沒有經過k-1這個點的松弛。
所以k要放在最外面
floyd雖然是最短路算法中最簡單基礎的一個,但永遠不要小看任何一個算法,每種算法都有著自己的智慧
轉載于:https://www.cnblogs.com/stargazer-cyk/p/10366536.html
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的最短路最基本算法———Floyd算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何写Emit代码
- 下一篇: countByValue