def first_non_zero(array)
first_non_zero = -1
array.each_with_index do |m,idx|
if m > 0
first_non_zero = idx
break
end
end
first_non_zero
end
def make_change(amount, coins = [25, 10, 5, 1])
puts "Amount: #{amount} coins: #{coins.inspect}"
coins = coins.sort.reverse
mins = coins.map {|c| amount / c }
exact_change = coins.map {|c| amount % c == 0 ? amount / c : -1 }
min_coins = exact_change.sort.find {|n| n > 0 } || (amount / coins.last)
optimum_change = []
while mins.find {|m| m > 0}
change = coins.map {|c| 0 }
coin_count = 0
fnz = first_non_zero(mins)
coin_count = mins[fnz]
current_amount = mins[fnz] * coins[fnz]
change[fnz] = coin_count
nci = fnz + 1
while nci < coins.length && coin_count < min_coins && current_amount < amount
amount_left = amount - current_amount
num_next = amount_left / coins[nci]
coin_count += num_next
current_amount += num_next * coins[nci]
change[nci] = num_next
nci = nci + 1
end
if current_amount == amount && coin_count <= min_coins
min_coins = coin_count
optimum_change << change.dup
end
mins[fnz] = mins[fnz] > min_coins ? min_coins : mins[fnz] - 1
end
result = []
optimum_change.each do |solution|
result = []
solution.each_with_index do |count, idx|
count.times { result << coins[idx] }
end
puts "#{result.inspect}: #{result.size} #{result.inject(0) {|sum, val| sum += val}}"
end
return result.size > 0 ? result : nil
end
make_change( 39)
make_change( 7, [5, 3] )
make_change(24,[10,8,2])
make_change(11,[10,9,2])
make_change(1023, (1..10).map{|n| 2**n})
make_change(497, [100, 99, 1])
make_change(397, [100, 99, 1])
make_change(297, [100, 99, 1])
make_change(1_000_001, [1_000_000, 2, 1])
make_change(4563, [97, 89, 83, 79, 73, 71, 67, 61, 59, 53, 47, 43, 41,
37, 31, 29, 23, 19, 17, 13, 11, 7, 5, 3])
make_change(1000001, [1000000, 1])
make_change(14, [10,7,1])
make_change(21, [10,7,1])
make_change(14, [10,5,3])