跳转至

Floyd 算法

Floyd 算法,使用动态规划来求解所有点对之间的最短路径。

设给定图的顶点集合 V={1,2,,n}V=\{1,2,\cdots,n\} 和边集合 EE,定义函数 f(k,u,v)f(k,u,v),表示只允许经过顶点 V={1,2,,k}V'=\{1,2,\cdots,k\},顶点 uu 到顶点 vv 的最短路径长度(uuvv 不一定在 VV' 中)。

k=0k=0 时,

f(0,u,v)={0如果 u=v+如果 uv 且 (u,v)Ew(u,v)如果 uv 且 (u,v)E f(0,u,v) = \begin{cases} 0 & \text{如果 } u = v \\ +\infin & \text{如果 } u \neq v \text{ 且 } (u,v) \notin E \\ w(u,v) & \text{如果 } u \neq v \text{ 且 } (u,v) \in E \end{cases}

k>0k>0 时,

f(k,u,v)=min(f(k1,u,v),f(k1,u,k)+f(k1,k,v)) f(k,u,v) = \min \big(f(k-1,u,v), f(k-1,u,k)+f(k-1,k,v)\big)

k=nk=n 时,f(n,u,v)f(n,u,v) 就是顶点 uu 到顶点 vv 的最短路径长度。

实现

/**
 * Floyd's algorithm.
 *
 * @param graph graph[u][v] is the length of the edge from u to v or {@code -1} if there is no edge.
 */
int[][] floyd(int[][] graph) {
    int n = graph.length;
    int[][] dp = new int[n][n];
    for (int u = 0; u < n; u++) {
        for (int v = 0; v < n; v++) {
            dp[u][v] = graph[u][v];
        }
    }

    for (int k = 1; k < n; k++) {
        for (int u = 0; u < n; u++) {
            for (int v = 0; v < n; v++) {
                if (dp[u][k] == -1 || dp[k][v] == -1) {
                    continue;
                }
                if (dp[u][v] == -1) {
                    dp[u][v] = dp[u][k] + dp[k][v];
                } else {
                    dp[u][v] = Math.min(dp[u][v], dp[u][k] + dp[k][v]);
                }
            }
        }
    }
    return dp;
}

算法的时间复杂度为 O(n3)O(n^3)

参考