Mae向きなブログ

Mae向きな情報発信を続けていきたいと思います。

ダイクストラ法

ダイクストラ法を作ってみました。
グラフは、ラベルつき隣接行列にしたのですが、辺が存在しないところを、nilで表現したのがまずかったです。条件判断などが繁雑になってしまいました。

threadの学習を兼ねて使ってみました。
dijkstra.rb

class Dijkstra
  attr_reader :result
  def initialize(g)
    @graph = g
  end

  def dijkstra(start)
    vertex = Array.new          # 頂点の集合
    @graph.size.times{|i| vertex << i}
    visited = Array.new         # 訪問済みの集合
    visited << start
    dist = @graph[start].dup    # dist[index]までの最短距離
    (@graph.size - 1).times do 
      # 未訪問の頂点からdist[w]が最小な頂点を選択
      w = search_vertex(vertex - visited, dist)
      if w != nil
        visited << w 
        (vertex - visited).each do |val|
          if @graph[w][val] && dist[val]
            dist[val] = if dist[val] < dist[w] + @graph[w][val]
                          dist[val]
                        else
                          dist[w] + @graph[w][val]
                        end
          elsif @graph[w][val]
            dist[val] = dist[w] + @graph[w][val]
          end
        end
      end
    end
    @result = dist
  end

  def search_vertex(v_s, d)
    min = nil
    v_s.each do |v|
      next if d[v] == nil
      min = d[v] if min == nil || min > d[v]
    end
    return nil if min == nil
    d.each_with_index do |val, idx|
      return idx if d[idx] == min
    end
  end
end

if __FILE__ == $0
  Graph = [[nil,  10, nil,  30, 100],
           [nil, nil,  50, nil, nil],
           [nil, nil, nil, nil,  10],
           [nil, nil,  20, nil,  60],
           [nil, nil, nil, nil, nil]]
  threads = []
  Graph.size.times do |i|
    threads << Thread.new(i) do |i|
      sleep(rand * 10)
      dijk = Dijkstra.new(Graph)
      dijk.dijkstra(i)
      print "#{i}: ", dijk.result.join(', '), "\n"
    end
  end
  threads.each{|t| t.join}
end

実行結果

mmasa@debian:~/work/ruby$ ruby dijkstra.rb
0: , 10, 50, 30, 60
4: , , , ,
3: , , 20, , 30
1: , , 50, , 60
2: , , , , 10

sleep(rand * 10)が効いているので、出力順がランダムになっています。出力が見にくいですが、例えば、頂点0からは、頂点1へ最短距離が10、頂点2へ最短距離が50…となっています。数字が表示されていないところへは、たどり着くことができません。頂点4からは、どこへも行けません。