I'm trying to create a program that takes a given sum and a given range of allowed addends and outputs the unique configurations of those addends which add up to the sum.
The use case is determining the possible combinations of different-sized multi-member districts to divide the members of a legislature into.
In a trivial example, given 15 legislators, and districts of minimum 3 and maximum 5 seats per district, the possible combinations are:
- [3, 3, 3, 3, 3]
- [4, 4, 4, 3]
- [5, 4, 3, 3]
- [5, 5, 5]
My initial thought was to start with the largest group of minimum-sized districts possible in a nested array, and add more entries by copying and modifying the previous entry. I don't know how to implement that approach, but I'm also not sure if it's even the right approach to this problem and I'm looking for suggestions.
def multi_member_districts
reps = 19
min = 3
max = 6
quomin, modmin = reps.divmod(min)
quomax, modmax = reps.divmod(max)
groups = Array.new(1) {Array.new}
(quomin - 1).times do groups[0].push(min) end
groups[0].unshift(min + modmin)
# PSEUDOCODE
# copy groups[i], insert copy at groups[i+1]
# remove the smallest element of groups[i+1] and spread it out across the other
# numbers in groups[i+1] in all configurations in which no element exceeds max
# check that there are no duplicate configurations
# repeat
puts "\nThe possible groups of districts are as follows:"
groups.each_index do |i|
(min..max).each do |j|
unless groups[i].count(j) == 0
puts ">> #{groups[i].count(j)} #{j}-member districts"
end
end
puts
puts "o-o-o-o-o-o-o-o-o-o-o-o-o-o"
end
end
multi_member_districts
EDIT_1: A less trivial example, 19 legislators, 3-6 seats per district --
- [4, 3, 3, 3, 3, 3]
- [4, 4, 4, 4, 3]
- [5, 5, 5, 4]
- [5, 4, 4, 3, 3]
- [5, 5, 3, 3, 3]
- [6, 5, 5, 3]
- [6, 4, 3, 3, 3]
- [6, 5, 4, 4]
- [6, 6, 4, 3]
EDIT_2: Clarified my question, cut down the code, hopefully more suitable