すべてのノードの最短経路のフロイドアルゴリズム:負の重みのエッジはありますが、負の重みのループはありません

フロイドワーシャルアルゴリズム(中国語ではフロイトアルゴリズムとも呼ばれます)は、任意の2点間の最短経路を解決するためアルゴリズムです。有向グラフまたは負の重み(ただし、負の重みループはありません)の最短経路問題を正しく処理できます。

1.画像の理解:(この部分は転載および整理されています)
元のテキストについては、ブログのパート2.2を参照して、最短経路の問題完全に理解してください
1.1。フロイドアルゴリズムの基本的な考え方:
ノードAからノードBへの最短経路は2つの可能性にすぎません:

  • 1は直接AからBまでです。
  • 2は、AからBにいくつかのノードを経由します。

したがって、dist(AB)はノードAからノードBへの最短経路距離であると想定します。各ノードKについて、dist(AK)+ dist(KB)<dist(AB)が真であるかどうかを確認します。 AからKへのパスは、AからBへのパスよりも短いため、dist(AB)= dist(AK)+ dist(KB)を設定します。これにより、すべてのノードを横断するときに、K、dist(AB )は、AからBへの最短経路距離です。

1.2。エラーコード:

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

しかし、ここではループのネスト順に注意を払う必要がありますすべてのノードKが最も内側のレベルでチェックされる場合、結果は正しくありません。このため、iからjへの最短パスは時期尚早に決定され、後でより短いパスが存在する場合、更新されなくなります。
例を見てみましょう。下の図を見てください
ここに画像の説明を挿入
。図の赤い数字はエッジの重みを表しています。最内層のすべてのノードKをチェックすると、A-> Bの場合、A-> Bのパスは1つしか見つかりません。パス距離は9で、これは明らかに正しくありません。実際の最短パスはA -> D-> C-> B、パス距離は6です。エラーの理由は、最内層のすべてのノードKをチェックしたため、AからBへの最短パスが時期尚早に決定されたためです。A-> Bからの最短パスが決定されたとき、dist(AC)は計算されませんでした。したがって、ループシーケンスを次のように書き換える必要があります
。ps:個人的には、これはセキュリティステータス(すべてのスレッドをテストする各リソース)とツリー配列の更新(すべての関連アイテムの更新)を判断するバンカーアルゴリズムと同じです。

1.3。正しいコード:

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。パス保存の問題:

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.原則と疑似コード:
ここに画像の説明を挿入

総括する:

1.動的プログラミングに基づいて、渡されたノードkがコードの最も外側のテストに配置されます。
2.フロイドワーシャルアルゴリズムの時間の複雑さはO(N 3)、空間の複雑さはO(N 2)です。

おすすめ

転載: blog.csdn.net/qq_33726635/article/details/106572966