prim

Ruby code posted by AndrewCap
created at 18 Dec 23:44

Edit | Back
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
require 'pp'
require 'benchmark'

def file 
  @file ||= File.readlines("edges.txt")
end

def header 
  @header ||= file.take(1)[0]
end

def number_of_nodes
  @number_of_nodes ||= header.split(" ")[0].to_i
end

def create_adjacency_matrix
  adjacency_matrix = [].tap { |m| number_of_nodes.times { m << Array.new(number_of_nodes) } }
  file.drop(1).map { |x| x.gsub(/\n/, "").split(" ").map(&:to_i) }.each do |(node1, node2, weight)|
    adjacency_matrix[node1 - 1][node2 - 1] = weight
    adjacency_matrix[node2 - 1][node1 - 1] = weight
  end
  adjacency_matrix
end

def find_cheapest_edge(adjacency_matrix, nodes_spanned_so_far, number_of_nodes)
  available_nodes = (0..number_of_nodes-1).to_a.reject { |node_index| nodes_spanned_so_far.include?(node_index + 1) }  
  
  cheapest_edges = available_nodes.inject([]) do |acc, node_index|
    get_edges(adjacency_matrix, node_index).select { |_, other_node_index| nodes_spanned_so_far.include?(other_node_index + 1) }.each do |weight, other_node_index|
      acc << { :start => node_index + 1, :end => other_node_index + 1, :weight => weight }
    end
    acc
  end
    
  cheapest_edges.sort { |x,y| x[:weight] <=> y[:weight] }.first
end

def get_edges(adjacency_matrix, node_index)
  adjacency_matrix[node_index].each_with_index.reject { |edge, index| edge.nil? }
end

def select_first_edge(adjacency_matrix)
  starting_node = 1
  cheapest_edges = get_edges(adjacency_matrix, 0).inject([]) do |all_edges, (edge, index)|
    all_edges << { :start => starting_node, :end => index + 1, :weight => edge }
    all_edges
  end
  cheapest_edges.sort { |x,y| x[:weight] <=> y[:weight] }.first
end

def nodes_left_to_cover
  (1..number_of_nodes).to_a - @nodes_spanned_so_far
end

# Prim's algorithm
Benchmark.bm (10){ |x|
x.report("fib1time: "){
  
  adjacency_matrix = create_adjacency_matrix
  first_edge = select_first_edge(adjacency_matrix)
  @nodes_spanned_so_far, @edges = [first_edge[:start], first_edge[:end]], [first_edge]

  while !nodes_left_to_cover.empty?
    cheapest_edge = find_cheapest_edge(adjacency_matrix, @nodes_spanned_so_far, number_of_nodes)
    @edges << cheapest_edge
    @nodes_spanned_so_far << cheapest_edge[:start]  
  end
  
  }
}

puts "MST:" 
pp @edges 

puts "cost #{ @edges.inject(0) {|acc, edge| acc + edge[:weight]} }"
2.31 KB in 8 ms with coderay