所有點對的最短路徑問題


定義:設G是一個有向圖,其中每條邊(i, j)都有一個非負的長度L[i, j],若點i 到點j 沒有邊相連,則設L[i, j] = ∞. 要找出每個頂點到其他所有頂點的最短路徑所對應的長度。

如:

 

 

則,L: 0  2  9

    8  0  6

    1  ∞   0

運用Floyd-Warshall算法, 時間復雜度為O(n3),空間復雜度為O(n2).

 

算法基本思路:

引理,點 i 到點 j 的最短路徑可能是點 i 到點 j 的直接路徑長度,也可能是以某點 k 為中間節點,i, k, j 的路徑長度。

采用自底向上逐步求解的方法,設D[i, j, k] 表示 點 i 到 j 以點集[0..k] 為中間節點的最短路徑。

k 從0開始枚舉各點,則第一步先求所有點以可能經過點0為中間節點的最短路徑;

第二步求所有點以可能經過點1為中間節點的最短路徑,在此時所有的D[i, j] 已經考慮過0作為中間節點的最短路徑,即第二步做的是以點集[0..1]作為考慮,滿足自底向上,不難看出,到了最后一步,就是以點集[0...n-1]作為考慮,此時求得的D[i, j] 就是最短路徑。

 

 

算法具體實現:

輸入:L[0...n-1][0...n-1]    L[i][j] 表示 i 到 j 的直接路徑長度

為了節約空間,可在原來的空間上做自底向上求解,即D只需二維。

首先初始化D[0...n-1][0...n-1],令 D[i][j] = L[i][j],無窮大的數就初始化為一個當前類型的最大值。

然后從0開始迭代k,D[i][j] = min(D[i][j], D[i][k] + D[k][j]),注意可能出現的無窮大值,即i 到 k 沒有直接路徑或k 到 j 沒有直接路徑,此時需要做比較,否則相加可能會出現“奇怪”的數字。

 

代碼:

/*
input: l[0..n-1][0..n-1]            //l[i][j] = the stright length between point i and j

table: d[0..n-1][0..n-1]            //d[i][j] = the minimum length between point i and j

enumerate k, 0<= k <=n-1, d[i][j] = min(l[i][j], d[i][k]+d[k][j])
*/

public class Floyd {
    
    public static int[][] floyd(int[][] l){
        int[][] d = new int[l.length][l.length];
        //init d[i][j] = l[i][j]
        for(int i = 0; i < d.length; i ++){
            System.arraycopy(l[i], 0, d[i], 0, d.length);
        }
        //compute
        for(int k = 0; k < d.length; k ++){
            for(int i = 0; i < d.length; i ++){
                for(int j = 0; j < d.length; j ++){
                    if(d[i][k] != Integer.MAX_VALUE && d[k][j] != Integer.MAX_VALUE)
                        d[i][j] = Math.min(d[i][j], d[i][k] + d[k][j]);
                }
            }
        }
        return d;
    }

    public static void main(String[] args) {
        int[][] l = {
                    {0, 7, 1, 6},
                    {Integer.MAX_VALUE, 0, 9, Integer.MAX_VALUE},
                    {4, 4, 0, 2},
                    {1, Integer.MAX_VALUE, Integer.MAX_VALUE, 0}
                    };
        int[][] d = floyd(l);
        for(int i = 0; i < d.length; i ++){
            for(int j = 0; j < d[i].length; j ++){
                System.out.print(d[i][j] + " ");
            }
            System.out.println();
        }
    }

}
Java

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM