所有点对的最短路径问题

定义:设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
原文地址:https://www.cnblogs.com/7hat/p/3430662.html