在圖論中,在尋路最短路徑中除了Dijkstra
算法之外,還有Floyd
算法也是很是經典,然而兩種算法仍是有區別
的,Floyd主要計算多源最短路徑。java
在單源正權值最短路徑,咱們會用Dijkstra算法來求最短路徑,而且算法的思想很簡單——貪心算法:每次肯定最短路徑的一個點而後維護(更新)這個點周圍點的距離加入預選隊列,等待下一次的拋出肯定。可是雖然思想很簡單,實現起來是很是複雜
的,咱們須要鄰接矩陣(表)儲存長度,須要優先隊列(或者每次都比較)維護一個預選點的集合。還要用一個boolean數組標記是否已經肯定、還要---------算法
總之,Dijkstra
算法的思想上是很容易接受的,可是實現上實際上是很是麻煩的。可是單源最短路徑沒有更好的辦法。複雜度也爲O(n2)
數組
而在n節點多源最短路徑中,若是從Dijkstra算法的角度上,只須要將Dijkstra封裝,而後執行n次Dijkstra算法便可,複雜度爲O(n3)
。可是這樣感受很臃腫,代碼量巨大,佔用不少空間內存。有沒有啥方法可以稍微變變口味呢?學習
答案是有的,這就是易寫但稍須要理解的Floyd
算法。一個求多元最短路徑算法。spa
先看看百度百科的定義吧:.net
Floyd算法又稱爲插點法,是一種利用動態規劃的思想尋找給定的加權圖中多源點之間最短路徑的算法,與Dijkstra算法相似。該算法名稱以創始人之1、1978年圖靈獎得到者、斯坦福大學計算機科學系教授羅伯特·弗洛伊德命名。3d
簡單的來講,算法的主要思想是動態規劃(dp),而求最短路徑須要不斷鬆弛
(熟悉spfa算法的可能熟悉鬆弛)。code
而算法的具體思想爲:cdn
鄰接矩陣dist
儲存路徑,同時最終狀態表明點點的最短路徑。若是沒有直接相連的兩點那麼默認爲一個很大的值(不要溢出)!而本身的長度爲0.第1個到第n個
點依次加入圖中。每一個點加入進行試探是否有路徑長度被更改。其中第三步的狀態轉移方程爲:blog
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j])
其中dp[x][y]
的意思能夠理解爲x到y的最短路徑。因此dp[i][k]
的意思能夠理解爲i到k的最短路徑dp[k][j]
的意思能夠理解爲k到j的最短路徑.我們圖解一個案例:
1
,你們能夠發現,因爲1的加入,使得原本不連通的2,3
點對和2,4
點對變得聯通,而且加入1後距離爲當前最小。(能夠很直觀加入5以後2,4,更短可是還沒加入)。爲了更好的描述其實此時的直接聯通點多了兩條。(2,3)和(2,4).咱們在dp中無論這個結果是經過前面那些步驟來的,可是在這個狀態,這兩點的最短距離就算它!
1
其中也使得3,1,4
這樣聯通,可是 3,1,4
聯通的話距離爲9遠遠大於原本的(3,4)
爲2,因此不進行更新。至於算法的模擬兩部核心已經告訴你們了,你們能夠自行模擬剩下的。
而對於程序而言,這個插入的過程至關簡單。核心代碼只有四行! 代碼以下
public class floyd {
static int max = 66666;// 別Intege.max 兩個相加越界爲負
public static void main(String[] args) {
int dist[][] = {
{ 0, 2, 3, 6, max, max },
{ 2, 0, max, max,4, 6 },
{ 3, max, 0, 2, max, max },
{ 6, max, 2, 0, 1, 3 },
{ max, 4, max, 1, 0, max },
{ max, 6, max, 3, max, 0 } };// 地圖
// 6個
for (int k = 0; k < 6; k++)// 加入滴k個節點
{
for (int i = 0; i < 6; i++)// 鬆弛I行
{
for (int j = 0; j < 6; j++)// 鬆弛i列
{
dist[i][j] = Math.min(dist[i][j], dist[i][k] + dist[k][j]);
}
}
}
// 輸出
for (int i = 0; i < 6; i++) {
System.out.print("節點"+(i+1)+" 的最短路徑");
for (int j = 0; j < 6; j++) {
System.out.print(dist[i][j]+" ");
}
System.out.println();
}
}
}
複製代碼
結果爲:
固然,在你學習的過程當中,能夠在每加入一個節點插入完成後,打印鄰接矩陣的結果,看看前兩部和筆者的是否相同(有助於理解
),若是相同,則說明正確!
你可能還會有疑惑,那咱麼就用一個局部性來演示一下,看其中AB最短距離變化狀況祝你理解:
好啦,Floyd算法就介紹到這裏,若是對你有幫助,請動動小手點個贊吧!蟹蟹。 但願和各位共同進步!歡迎關注筆者公衆號:bigsai
!