Floyd Warshall的算法为何成功?

问题描述

如何阻止在经过迭代的更早的外部循环的后续迭代(遍历所有可能的中间顶点)中找到更好的中间路径?

解决方法

我认为您对Floyd-Warshall算法的工作方式有误解。作为参考,这是一个实现(来自https://cp-algorithms.com/graph/all-pair-shortest-path-floyd-warshall.html):

for (int k = 0; k < n; ++k) {
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            d[i][j] = min(d[i][j],d[i][k] + d[k][j]); 
        }
    }
}

最外面的循环不会在所有中间顶点上循环。计算从ij的最短路径时,最外面的循环定义了一组顶点,这些顶点可以是从ij的路径的一部分。特别是,如果我们标记n顶点1,2,3,...,n,则k的值指定在该迭代中我们只能访问集合{1,k}的顶点。您可以看到,k -> n的值d[i][j]最终收敛到我们的解决方案中(因为应该允许使用真正的“最短路径”将任何顶点用作中间值)。

为什么我们要用这种方式分解它?因为如果我们知道固定值k的解决方案,那么我们可以轻松地构造k + 1的解决方案。这是动态编程的关键原则,您应该尝试了解循环d[i][j] = min(d[i][j],d[i][k] + d[k][j])如何耗尽所有可能性。

现在可以更直接地直接回答您的问题,使用集{1,k}的新计算路径是否使用最外层循环的上一次迭代的结果也没关系。这是正确的,因为集合{1,k - 1}{1,k}的子集,因此如果我们确实重用了之前缩短的计算路径,那将是非常好的。关键思想是我们具有 option 来使用新添加的顶点k