Floyd-Warshall算法

时间:2013-01-26 21:38:59

标签: algorithm floyd-warshall

是否有一个简单的解释为什么这个片段找到两个顶点之间的最短距离

for (k = 0; k < n; ++k)
  for (i = 0; i < n; ++i)
    for (j = 0; j < n; ++j)
      if (d[i][k] + d[k][j] < d[i][j])
        d[i][j] = d[i][k] + d[k][j]

这不是

for (i = 0; i < n; ++i)
  for (j = 0; j < n; ++j)
    for (k = 0; k < n; ++k)
      if (d[i][k] + d[k][j] < d[i][j])
        d[i][j] = d[i][k] + d[k][j]

(对于k是第二个片段中最里面的一个)

4 个答案:

答案 0 :(得分:4)

因为我们的目的是尝试在每个步骤中通过节点k来改善路径,以便改进每个i - j路径。

符号无关紧要,如果需要,可以使用i, j, k作为循环变量而不是k, i, j,但必须牢记逻辑。在这种情况下,您需要尝试通过在每个步骤中执行j - k来改进i路径:

for i = 0, n
  for j = 0, n
    for k = 0, n
      if d[j, i] + d[i, k] < d[j, k]
        d[j, k] = d[j, i] + d[i, k]

你不能只是在不改变条件的情况下重新排序for循环,因为你得到了一种不同的算法 - 谁知道它的作用。

答案 1 :(得分:2)

for (k = 0; k < n; ++k)
  for (i = 0; i < n; ++i)
    for (j = 0; j < n; ++j)
      if (d[i][k] + d[k][j] < d[i][j])
        d[i][j] = d[i][k] + d[k][j]

最外层循环k指的是可能位于ViVj之间的路径上的顶点。因此,在k=1时,您正在考虑包含顶点Vi的顶点VjV1之间的所有路径,如

Vi .... V1 .... Vj

更重要的是,从这些路径中你选择最好的放松

if (d[i][k] + d[k][j] < d[i][j])
        d[i][j] = d[i][k] + d[k][j]

同样,每次迭代都集中在两个顶点ViVj上,并选择它们之间的最佳路径。

在你的另一个例子中,失败的那个,你不是在两个固定顶点ViVj之间的路径中选择最好的,而是你在整个地方放松,从不等待足够长的时间找出两个设置顶点之间哪条路径最好。

On Geekviewpoint, a site which I rely on a lot,他们明确地使用xv作为顶点,并使用t作为最外层循环,这样可以很容易地记住t是临时的所以没有一个端点。 (我希望他们实际上已经解释过了,因为对每个人来说都不是很明显。)

//dynamically find the shortest distance between each pair.
    for (int t = 0; t < n; t++) {
      for (int v = 0; v < n; v++) {
        for (int u = 0; u < n; u++) {
          if (dist[v][u] > (long) dist[v][t] + dist[t][u]) {
            dist[v][u] = dist[v][t] + dist[t][u];
            pred[v][u] = pred[t][u];
          }
        }
      }
    }

答案 2 :(得分:0)

我找到了第二个有缺陷算法的反例 当i = 0,j = 1时,它会尝试找一个中介,但没有 然后,当中间人可用于i = 0,j = 1时,不再再次检查。 enter image description here

答案 3 :(得分:0)

基本上,当您在K中具有loop k值时,这意味着您将要添加另一条边,并且使用边(i->j)更新了从(1->K-1)出发的所有可能方式。 然后插入另一条边K,然后再次检查是否有任何便宜的方法可以使用此边从(i->j)出发。所以你写d[i][j]=min(d[i][j],d[i][k]+d[k][j])

所以,如果你想写

  for(int i=0;i<n;i++)
   for(int j=0;j<n;j++)
     for(int k=0;k<n;k++)

您的更新应为d[j][k] = min(d[j][k],d[j][i]+d[i][k])