カテゴリー別アーカイブ: 蟻本

[Ruby] ワーシャルフロイド法


名前も実装もかっこいいアルゴリズムのワーシャルフロイド法をrubyで実装する。

重み付きで有向な、しかもコストが正の場合に、全点間の最小コストを非常に簡潔にかくことができるもの。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
INF = 9999999.freeze

nodes_size = gets.chomp.to_i.freeze
edges_size = gets.chomp.to_i.freeze
edges = []

# nodes初期化
nodes_size.times do |i|
  nodes_size.times do |j|
    edges[i] ||= []
    edges[i][j] = INF
  end
  edges[i][i] = 0
end

# データ読み込み
edges_size.times do |i|
  edge = gets.split(' ').map(&:to_i)
  edges[edge[0]] ||= []
  edges[edge[0]][edge[1]] = edge[2]
end

# ワーシャルフロイド
nodes_size.times do |i|
  nodes_size.times do |j|
    nodes_size.times do |k|
      edges[i][j] = [edges[i][j], edges[i][k] + edges[k][j]].min
    end
  end
end

標準入力からの入力例を用意した。
こんなグラフになっている。

graph

1
2
3
4
5
6
7
8
9
10
11
12
13
14
5
12
0 1 1
1 0 1
0 2 5
2 0 5
1 2 3
2 1 3
1 4 3
4 1 3
2 3 6
3 2 6
3 4 5
4 3 5

実際のアルゴリズムは23行目以降で、ただの3重ループで実装が終わってしまう。
edges[i][j]に格納されるものは、i点からj点への最小コストとなる。
edgesには初期状態では入力として与えられた経路しかないけれども、キモとなっている27行目を見てみると、iからjへの最小コストiからkの最小コスト+kからjへの最小コストを比較して小さい方でedges[i][j]を更新している。

この中間点kを置くという発想がイケメンですね。