Skip to content
Go back

ワーシャルフロイド法

· Updated:

重み付きグラフにおけるすべての頂点間の最短経路を計算する

  • 入力:グラフG=(V,E)G = (V, E)
  • 出力:i,jVi,j \in V間の最短経路
  • 計算量:O(V3)O(V^3)

概要

kVk \in Vとして、すべてのi,jVi,j \in Vに対して、

  • iiからjjへの経路pi,jp_{i,j}を通るコストci,jc_{i,j}
  • iiからkkを経由してjjへ向かう経路pi,k,jp_{i,k,j}を通るコストci,k,jc_{i,k,j}

の小さい方をiiからjjへの経路のコストとして選択する。 これをすべてのkkについて行うと、すべてのi,jVi,j\in Vに対する最短経路を得られる。

解釈

k=nk = nのとき、ci,jc_{i,j}pi,jp_{i,j}の道中に頂点0,1,...,n1,n{0, 1, ..., n-1, n}のみを含むときの最短経路を表す。

コード

// V = {0, 1, ..., N - 1}のときのワーシャルフロイド法
Array2D<uint64_t> warshall_floyd(const Graph& graph) {
  const size_t N = graph.vertex_count();  // 頂点数
  Array2D<uint64_t> distances(N, N);  // NxNの2次元配列

  // 初期化
  for (size_t i = 0; i < N; ++i) {
    for (size_t j = 0; j < N; ++j) {
      if (i == j) {
        // 自分自身への距離は0になる
        distances[i][j] = 0;
      } else if (graph.has_edge(i, j)) {
        // グラフがiからjへの辺を持っていれば、その辺の重みを使う
        distances[i][j] = graph.edge(i, j);
      } else {
        // それ以外ならば、到達できないことを表す大きな値を使う
        distances[i][j] = UINT64_MAX;
      }
    }
  }

  // 最短経路を計算する
  for (size_t k = 0; k < N; ++k) {
    for (size_t i = 0; i < N; ++i) {
      for (size_t j = 0; j < N; ++j) {
        distances[i][j] = std::min(distances[i][j], distances[i][k] + distances[k][j]);
      }
    }
  }

  return distances;
}