I've written the following code to find the connected components of a graph in ruby, but it is quite slow since I don't use any sensible data structure for the disjoint sets, and hence find_set is probably \$O(n^2)\$ (don't know the complexity for enumerable.find in Ruby).
Can anybody help me improve it? I am relatively new to ruby, and so would appreciate any insights. This code is meant to solve the problem posed Here:
My solution, in plain English, is the find the number of connected components in the graph given, then either calculate the cost of building a library in every node or the cost of building a library in each connected component plus the cost of building the roads for the minimum spanning tree of each component.
The Code
#!/bin/ruby
require 'set'
def roadsAndLibraries(n, c_lib, c_road, cities)
vertices = make_set((1..n).to_a)
#find connected components
cities.each do |a, b|
first_set = find_set(vertices, a)
second_set = find_set(vertices, b)
if first_set != second_set
vertices.add(first_set | second_set)
vertices.delete(first_set)
vertices.delete(second_set)
end
end
#calculate the cost of building the edges required for a MST of each component
roads_cost = c_road * vertices.to_a.map{|x| x.size - 1}.inject(:+)
if c_road > c_lib
return n * c_lib
else
return vertices.size * c_lib + roads_cost
end
end
#takes an array of integers, and maps them into a set of singleton sets containing each node number
def make_set(arr_n)
vertices = Set.new
for i in 1..arr_n.size
vertices.add([i])
end
vertices.map!{|x| x.to_set}
end
#finds set containing a given node value
def find_set(set, node)
set.find{|x| x.include?(node)}
end
# q is number of queries, n is the number of vertices in the graph
q = gets.strip.to_i
for a0 in (0..q-1)
n, m, c_lib, c_road = gets.strip.split(' ')
n = n.to_i
m = m.to_i
c_lib = c_lib.to_i
c_road = c_road.to_i
cities = Array.new(m)
for cities_i in (0..m-1)
cities_t = gets.strip
cities[cities_i] = cities_t.split(' ').map(&:to_i)
end
result = roadsAndLibraries(n, c_lib, c_road, cities)
puts result
end