フロイドワーシャルアルゴリズム(中国語ではフロイトアルゴリズムとも呼ばれます)は、任意の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)です。