本文參考http://blog.csdn.net/ochangwen/article/details/50730937,
1.定義概覽
Floyd-Warshall算法(Floyd-Warshall algorithm)又稱爲插點法是解決任意兩點間的最短路徑的一種算法,可以正確處理有向圖或負權的最短路徑問題,同時也被用於計算有向圖的傳遞閉包。Floyd-Warshall算法的時間複雜度爲O(N3),空間複雜度爲O(N2)。
2.算法描述:
1)算法思想原理:
Floyd算法是一個經典的動態規劃算法。用通俗的語言來描述的話,首先我們的目標是尋找從點i到點j的最短路徑。從動 態規劃的角度看問題,我們需要爲這個目標重新做一個詮釋(這個詮釋正是動態規劃最富創造力的精華所在), 從任意節點i到任意節點j的最短路徑不外乎2種可能,1是直接從i到j,2是從i經過若干個節點k到j。所以,我們假設
Dis(i,j)爲節點u到節點v的最短路徑的距離,對於每一個節點k,我們檢查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,證明從i到k再到j的路徑比i直接到j的路徑
短,我們便設置Dis(i,j) = Dis(i,k) + Dis(k,j),這樣一來,當我們遍歷完所有節點k,Dis(i,j)中記錄的便是i到j的最短路徑的距離。
2).算法描述:
a.從任意一條單邊路徑開始。所有兩點之間的距離是邊的權,如果兩點之間沒有邊相連,則權爲無窮大。
b.對於每一對頂點 u 和 v,看看是否存在一個頂點 w 使得從 u 到 w 再到 v 比己知的路徑更短。如果是更新它。
3).Floyd算法過程矩陣的計算----十字交叉法
補充其中用到的十字交叉法如下:
先來簡單分析下,由於矩陣中對角線上的元素始終爲0,因此以k爲中間點時,從上一個矩陣到下一個矩陣變化時,矩陣的第k行,第k列和對角線上的元素是不發生改變的(對角線上都是0,因爲一個頂點到自己的距離就是0,一直不變;而當k爲中間點時,k到其他頂點(第k行)和其他頂點到k(第k列)的距離是不變的)。
因此每一步中我們只需要判斷4*4-3*4+2=6個元素是否發生改變即可,也就是要判斷既不在第k行第k列又不在對角線上的元素。具體計算步驟如下:以k爲中間點(1)“三條線”:劃去第k行,第k列,對角線(2)“十字交叉法”:對於任一個不在三條線上的元素x,均可與另外在k行k列上的3個元素構成一個2階矩陣,x是否發生改變與2階矩陣中不包含x的那條對角線上2個元素的和有關,若二者之和小於x,則用它們的和替換x,對應的Path矩陣中的與x相對應的位置用k來替代。。。
具體實例及代碼如下所示:
/** * @Title: Floyd.java * @Package dynamicprogramming * @Description: TODO * @author peidong * @date 2017-6-13 上午9:23:39 * @version V1.0 */ package dynamicprogramming; /** * @ClassName: Floyd * @Description: 弗洛伊德最短路徑算法 * @date 2017-6-13 上午9:23:39 * */ public class Floyd { public static void shorestFloyd(){ int MAX_VALUE = 65535; int[][] edgesMatrix ={{0, 5, MAX_VALUE, 7}, {MAX_VALUE, 0, 4, 2}, {3, 3, 0, 2}, {MAX_VALUE, MAX_VALUE, 1, 0}}; int n = 4;//vertexSize; 結點個數 int[][] tc = new int[n][n]; //保存從i到j的最短路徑值 int[][] p = new int[n][n]; //保存經過的中間結點 //初始化tc,p for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ p[i][j] = -1; tc[i][j] = edgesMatrix[i][j]; //便矩陣 } } //進行Floyd算法,從0到n-1所有可能進行遍歷 for(int x = 0; x < n; x++){ //x表示中間結點 for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ if(tc[i][j] > tc[i][x] + tc[x][j]){ tc[i][j] = tc[i][x] + tc[x][j]; p[i][j] = x; } } } } // 下面對獲得的結果進行展示 System.out.println("最短路徑狀態轉移矩陣爲:"); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { System.out.print(" " + tc[i][j]); } System.out.println(); } System.out.println("對應的結點矩陣爲:"); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { System.out.print(" " + p[i][j]); } System.out.println(); } // System.out.println("+++++++++++++++++++++++++++++++++++"); /* for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { System.out.println("輸出i=" + i + "到j=" + j + "最短路徑:"); int k = p[i][j]; if (k == -1) { System.out.println("沒有最短路徑"); } else { System.out.print(" " + k); while (k != j) { k = p[k][j]; System.out.print(" " + k); } System.out.println(" "+k); System.out.println(); } } } */ } /** * @Title: main * @Description: 測試用例 * @param args * @return void * @throws */ public static void main(String[] args) { // TODO Auto-generated method stub shorestFloyd(); } }