简体   繁体   中英

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)

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.

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. In that case, you will want to try to improve the j - k paths by going through i at each step:

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.

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 . So when k=1 , for example, you are considering all paths between vertices Vi and Vj that include vertex V1 as in

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.

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.

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. (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.
Then when an intermediary would be available for i=0, j=1 it is no longer checked again.在此处输入图片说明

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) . 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 . so you write 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])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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