Skip to content

Instantly share code, notes, and snippets.

@takehiko
Created June 14, 2016 21:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save takehiko/49e2198ec974d326f7f17e9fee4199c4 to your computer and use it in GitHub Desktop.
Save takehiko/49e2198ec974d326f7f17e9fee4199c4 to your computer and use it in GitHub Desktop.
Divide amount equally using pairwise equalization
#!/usr/bin/env ruby
# balancing.rb : Divide amount equally using pairwise equalization
# by takehikom
class Balancing
def initialize(n_, rep_ = 5)
@n = n_
@rep = rep_
@zero = Rational(0, 1)
@one = Rational(1, 1)
@minus = Rational(-1, 1)
@average = Rational(1, @n)
@cups = [@zero] * @n
@cups[0] = @one
end
def to_s
emax = error
lines = []
@cups.each_with_index do |cup, i|
lines << "#{diff(cup) == emax ? '*' : ' '}[#{i + 1}] #{cup} = #{cup.to_f}"
end
lines << "error: #{emax} = #{emax.to_f}"
lines.join("\n")
end
def equalize(i, j)
sum = @cups[i] + @cups[j]
avg = sum / 2
@cups[i] = @cups[j] = avg
end
def diff(cup)
(cup < @average) ? (@average - cup) : (cup - @average)
end
def error
pos = 0
emax = @zero
@cups.each_with_index {|cup, i|
e = diff(cup)
if emax < e
pos = i
emax = e
end
}
emax
end
def balanced?
error == 0
end
def find_min_and_max
pos_min = pos_max = -1
min = @one
max = @minus
@cups.each_with_index {|cup, i|
if cup < min
pos_min = i
min = cup
end
if max < cup
pos_max = i
max = cup
end
}
raise if pos_min == -1
raise if pos_max == -1
raise if min >= max
[pos_min, pos_max]
end
def start
puts "==== Step 0 ===="
puts to_s
@rep.times do |trial|
i, j = find_min_and_max
equalize(i, j)
puts "==== Step #{trial + 1} ===="
puts to_s
if balanced?
puts "==== End of operation ===="
break
end
end
end
end
if __FILE__ == $0
n = (ARGV.shift || 3).to_i
rep = (ARGV.shift || 5).to_i
Balancing.new(n, rep).start
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment