Floyd算法是大二到大三期間集訓時候纔算真正接觸的,或許只有前一段時間DP的積累現在纔算是真正理解
這個算法需要充分理解DP的滾動數組思想才能算是真正的掌握
Floyd算法又稱爲插點法
算法的目標是要求圖中所有兩個點的最短距離,就用dis[i][j]來表示
但是dis[i][j]是不夠設置爲狀態的,因爲這個狀態比較粗略,狀態之間無法轉換
這裏就加了一個很神奇的限制條件,然後形成了這個狀態:dis[i][j][k]表示從i到j的最短路,並且這條路上的點只能經過編號爲0-k這些點,所以光求出某個dis[i][j][*]還不行,必須要dis[i][j][N]纔等於 i 到 j 的最短距離。
d[i][j][k]表示從i到j途中只允許經過[0,k]這些節點時的最短距離;
這個k是代表編號,不是有k個
i到j的最短路中不經過k點時:dis[i][j][k] = dis[i][j][k-1]
經過:dis[i][j][k] = dis[i][k][k-1]+dis[k][j][k-1]
所以dis[i][j][k] = min(dis[i][j][k-1],dis[i][k][k-1]+dis[k][j][k-1]);
這裏就可以差不多有爲什麼FLOYD能求出最短路的感覺了,因爲其實它也是靠K把一個個中間點試過來的。
這樣一看就可以用滾動數組了,簡化爲dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j]);
Floyd的初始化問題:dis[i][j]若i,j有直接相連的邊則初始化爲邊權,沒有則初始化爲INF(求最小路徑時),-INF(求最大路徑時)
Floyd的路徑輸出:
記錄路徑肯定是得再用一個數組了,一維的肯定是不夠的,連從誰到誰都表示不出來
使用path[i][j],path[i][j]表示從i到j的最短路中,i的下一個點是誰k,這樣就可以path[i][j] = k,path[k][j]順藤摸瓜把整條路都解決了