動態規劃實例(十五):最短路徑Floyd

    本文參考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();
    }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章