Floyd algorithm for the shortest path of all nodes: there can be negative weight edges, but no negative weight loops

Floyd-Warshall algorithm , also known as Freud's algorithm in Chinese , is an algorithm for solving the shortest path between any two points . It can correctly handle the shortest path problem of directed graphs or negative weights (but no negative weight loops).

1. Understanding of the image: (This part is reprinted and organized) For the
original text, see: Part 2.2 of the blog to thoroughly understand the shortest path problem .
1.1. The basic idea of ​​the Floyd algorithm:
the shortest path from any node A to any node B is nothing more than 2 possibilities:

  • 1 is directly from A to B;
  • 2 is from A to B through several nodes.

Therefore, we assume that dist(AB) is the shortest path distance from node A to node B. For each node K, we check whether dist(AK) + dist(KB) <dist(AB) is true. If so, prove from The path from A to K to B is shorter than the path from A to B directly, so we set dist(AB) = dist(AK) + dist(KB), so that when we traverse all nodes K, dist(AB ) Is the shortest path distance from A to B.

1.2. Error code:

for (int i=0; i<n; ++i) {
    
    
  for (int j=0; j<n; ++j) {
    
    
    for (int k=0; k<n; ++k) {
    
    
      if (dist[i][k] + dist[k][j] < dist[i][j] ) {
    
    
        dist[i][j] = dist[i][k] + dist[k][j];
      }
    }
  }
}

But here we should pay attention to the nesting order of the loop. If all nodes K are checked at the innermost level, the result will be incorrect. Why? Because of this, the shortest path from i to j is determined prematurely, and when there is a shorter path later, it will no longer be updated.
Let's look at an example, look at the picture below: the
Insert picture description here
red numbers in the figure represent the weights of the edges. If we check all nodes K in the innermost layer, then for A->B, we can only find one path, that is, A->B, and the path distance is 9, which is obviously incorrect. The real shortest path is A ->D->C->B, the path distance is 6.The reason for the error is that we checked all nodes K in the innermost layer, which caused the shortest path from A to B to be determined prematurely. When the shortest path from A->B was determined, dist(AC) had not been calculated.. Therefore, we need to rewrite the loop sequence as follows:
ps: Personally, this is the same idea as the banker algorithm judging the security status (each resource to test all threads) and the tree array update (update all related items).

1.3. Correct code:

for (int k=0; k<n; ++k) {
    
    
  for (int i=0; i<n; ++i) {
    
    
    for (int j=0; j<n; ++j) {
    
    
            /*
            实际中为防止溢出,往往需要选判断 dist[i][k]和dist[k][j
            都不是Inf ,只要一个是Inf,那么就肯定不必更新。 
            */
      if (dist[i][k] + dist[k][j] < dist[i][j] ) {
    
    
        dist[i][j] = dist[i][k] + dist[k][j];
      }
    }
  }
}

1.4. Path saving problem:

void floyd() {
    
    
      for(int i=1; i<=n ; i++){
    
    
        for(int j=1; j<= n; j++){
    
    
          if(map[i][j]==Inf){
    
    
               path[i][j] = -1;//表示  i -> j 不通 
          }else{
    
    
               path[i][j] = i;// 表示 i -> j 前驱为 i
          }
        }
      }
      for(int k=1; k<=n; k++) {
    
    
        for(int i=1; i<=n; i++) {
    
    
          for(int j=1; j<=n; j++) {
    
    
            if(!(dist[i][k]==Inf||dist[k][j]==Inf)&&dist[i][j] > dist[i][k] + dist[k][j]) {
    
    
              dist[i][j] = dist[i][k] + dist[k][j];
              //path[i][k] = i;//删掉
              path[i][j] = path[k][j];
            }
          }
        }
      }
    }
    void printPath(int from, int to) {
    
    
        /*
         * 这是倒序输出,若想正序可放入栈中,然后输出。
         * 
         * 这样的输出为什么正确呢?个人认为用到了最优子结构性质,
         * 即最短路径的子路径仍然是最短路径
         */
        while(path[from][to]!=from) {
    
    
            System.out.print(path[from][to] +"");
            to = path[from][to];
        }
    }

2. Principle and pseudo code:
Insert picture description here

to sum up:

1. Based on dynamic programming, the passed node k is placed in the outermost test in the code.
2. The time complexity of the Floyd-Warshall algorithm is O(N 3 ), and the space complexity is O(N 2 ).

Guess you like

Origin blog.csdn.net/qq_33726635/article/details/106572966