JavaScriptで学ぶワーシャル・フロイド法(全点対最短経路アルゴリズム)
全点対最短経路問題とは
ダイクストラ法(Dijkstra's algorithm)は、ある1つのノードから他のすべてのノードへの最短距離・経路を求めるためのアルゴリズムです。しかし、実務では「すべてのノードから、それ以外のすべてのノードへの最短経路」をまとめて求めたいケースがあります。こうした問題に活躍するのが全点対最短経路(All Pairs Shortest Path)アルゴリズムであり、その中で最も広く利用されているのがワーシャル・フロイド法(Floyd-Warshall algorithm)です。
ワーシャル・フロイド法の仕組み
ワーシャル・フロイド法は、以下の手順で動作します。
- N × N の距離行列を無限大(Infinity)で初期化します。
- 各辺 u, v について、行列にその辺の重みを設定します。また、自分自身への辺 v, v については距離を 0 に設定します。
- i、j、k を反復子とする3重のループを作成します。各ノード i から各ノード j への距離に対して、「ノード k を経由したほうが近回線になるか」を検討し、既存の arr[i][j] より小さい値が見つかれば距離を更新します。
なお、ここでは行列の代わりにオブジェクトを使用します。複雑なオブジェクトで各ノードを表現する場合でも、インデックスを意識せずに扱えるためです。
計算量は O(n³) となるため、グラフが大規模になる場合は注意が必要ですが、小〜中規模のグラフなら非常にシンプルかつ効果的な手法です。
それでは、実際の実装を見ていきましょう。
実装例
floydWarshallAlgorithm() {
let dist = {};
for (let i = 0; i < this.nodes.length; i++) {
dist[this.nodes[i]] = {};
// 既存の辺にはその重みを距離として設定
this.edges[this.nodes[i]].forEach(e => (dist[this.nodes[i]][e.node] = e.weight));
this.nodes.forEach(n => {
// その他のノードには無限大を設定
if (dist[this.nodes[i]][n] == undefined)
dist[this.nodes[i]][n] = Infinity;
// 自分自身への距離は0に設定
if (this.nodes[i] === n) dist[this.nodes[i]][n] = 0;
});
}
this.nodes.forEach(i => {
this.nodes.forEach(j => {
this.nodes.forEach(k => {
// i → k → j の経由が i → j の直接移動より短いか確認し、
// 短ければ i → j の値を新しい値で更新する
if (dist[i][k] + dist[k][j] < dist[i][j])
dist[i][j] = dist[i][k] + dist[k][j];
});
});
});
return dist;
}
}動作確認
次のコードで動作を確認できます。
使用例
let g = new Graph();
g.addNode("A");
g.addNode("B");
g.addNode("C");
g.addNode("D");
g.addEdge("A", "C", 100);
g.addEdge("A", "B", 3);
g.addEdge("A", "D", 4);
g.addEdge("D", "C", 3);
console.log(g.floydWarshallAlgorithm());出力結果
このコードを実行すると、次の出力が得られます。
{
A: { C: 7, B: 3, D: 4, A: 0 },
B: { A: 3, B: 0, C: 10, D: 7 },
C: { A: 7, D: 3, B: 10, C: 0 },
D: { A: 4, C: 3, B: 7, D: 0 }
}結果を見ると、たとえば A から C への直接の辺の重みは 100 ですが、D を経由する経路(A → D → C)を使うことで距離 7 に短縮されていることがわかります。このように、ワーシャル・フロイド法はすべてのノード間の最短距離を1度の処理で効率的に求めることができる強力なアルゴリズムです。
-
JavaScriptのdebuggerステートメントの使い方を徹底解説
JavaScriptのdebuggerステートメントは、コード内にブレークポイントを設定するための構文です。実行中のコードがdebuggerステートメントに到達すると、その時点で処理が一時停止し、開発者ツールのデバッガーが利用可能であれば自動的にデバッガー機能が呼び出されます。 debuggerステートメントの基本動作 debuggerステートメントは、以下のような場面で特に役立ちます。 コードの特定の箇所で処理を止めて、変数の値を確認したいとき ループ処理の各ステップを詳細に追跡したいとき 複雑なロジックの不具合原因を特定したいとき なお、ブラウザの開発者ツール(DevTools)が開い
-
JavaScriptのImage()オブジェクトとは?使い方とサンプルコードを解説
JavaScriptにおけるImage()オブジェクトは、HTMLの<img>要素を表すオブジェクトです。このオブジェクトを使うことで、JavaScriptから動的に画像を生成し、Webページに追加することができます。Image()コンストラクタには、引数として画像の幅と高さをピクセル単位で指定できます。また、生成した画像オブジェクトのsrcプロパティに画像のURLを設定することで、画像を読み込むことが可能です。Image()オブジェクトの基本的な使い方以下は、JavaScriptでImage()オブジェクトを使用するサンプルコードです。コード例<!DOCTYPE html&