简体   繁体   English

Floyd-Warshall 算法

[英]Floyd–Warshall algorithm

Is there a simple explanation for why this snippet finds the shortest distance between two vertices是否有一个简单的解释来解释为什么这个片段找到两个顶点之间的最短距离

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]

and this doesn't而这并没有

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]

( for k is the innermost one in the second snippet) (因为 k 是第二个片段中最里面的一个)

Because the idea is to try to make paths better by trying to go through node k at each step in order to improve every i - j path.因为这个想法是通过在每一步尝试通过节点k来尝试使路径更好,以改进每条i - j路径。

The notations do not matter, you can use i, j, k as the loop variables instead of k, i, j if you want, but you must keep the logic above in mind.符号无关紧要,如果需要,您可以使用i, j, k作为循环变量而不是k, i, j ,但您必须牢记上述逻辑。 In that case, you will want to try to improve the j - k paths by going through i at each step:在这种情况下,您将希望通过在每个步骤中通过i来尝试改进j - k路径:

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]

You cannot just reorder the for loops without also changing the condition because you get a different algorithm that way - who knows what it does.您不能只对 for 循环重新排序而不更改条件,因为这样会得到不同的算法 - 谁知道它的作用。

In

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]

The outermost loop k is referring to vertices that may be on the path between Vi and Vj .最外面的循环k指的是可能在ViVj之间的路径上的顶点。 So when k=1 , for example, you are considering all paths between vertices Vi and Vj that include vertex V1 as in因此,例如,当k=1时,您正在考虑包含顶点V1顶点ViVj之间的所有路径,如

Vi .... V1 .... Vj

More importantly, from among those paths you are choosing the best with the relaxation更重要的是,从这些路径中,您选择了最好的放松方式

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

Again, each iteration is focussed on two vertices Vi and Vj and in chooses the best path between them.同样,每次迭代都集中在两个顶点ViVj并在它们之间选择最佳路径。

In your other instance, the one that fails, you are not choosing the best among paths between two fixed vertices Vi and Vj , instead you are relaxing all over the place, never waiting long enough to find out which path between two set vertices is the best.在您的另一个实例中,失败的那个,您没有在两个固定顶点ViVj之间的路径中选择最佳路径,而是到处放松,永远不会等待足够长的时间来找出两个集合顶点之间的哪条路径是最好。

On Geekviewpoint, a site which I rely on a lot , they distinctively use x and v as vertices and t for the outermost loop, which makes it easy to remember that t is temporary and so not one of the endpoints. 在我非常依赖的 Geekviewpoint 网站上,他们特别使用xv作为顶点,将t用作最外层循环,这使得很容易记住t是临时的,因此不是端点之一。 (I wish they had actually explained it, since it's not obvious to everyone.) (我希望他们真的解释过了,因为这对每个人来说都不是很明显。)

//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];
          }
        }
      }
    }

I found a counterexample for the second flawed algorithm.我找到了第二个有缺陷的算法的反例。
When i=0, j=1 it will try to find an intermediary, but there isn't any.当 i=0, j=1 时,它会尝试寻找中介,但没有中介。
Then when an intermediary would be available for i=0, j=1 it is no longer checked again.然后,当 i=0, j=1 的中介可用时,不再检查它。在此处输入图片说明

Basically when you have K value in loop k that means You are about to add another edge and all possible way to go from (i->j) is updated using edges (1->K-1) .基本上,当您在loop k中有K值时,这意味着您将要添加另一条边,并且从(i->j)出发的所有可能方式都使用边(1->K-1) Then you insert another edge K and you again check if there is any way to go from (i->j) in cheaper way using this edge .然后插入另一条边K并再次检查是否有任何方法可以使用此边以更便宜的方式从(i->j)出发。 so you write d[i][j]=min(d[i][j],d[i][k]+d[k][j]) .所以你写d[i][j]=min(d[i][j],d[i][k]+d[k][j])

So if you want to write所以如果你想写

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

Your update should be d[j][k] = min(d[j][k],d[j][i]+d[i][k])你的更新应该是d[j][k] = min(d[j][k],d[j][i]+d[i][k])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM