I am working on a set partitioning problem and need a way to define all combinations of unordered bucket sizes. Given N elements and exactly M groups, find every combination of group sizes such that the sum of the group sizes is N. Note: The size of the bucket cannot be 0.
For example, assume 6 items need to be placed in 3 buckets. The solution I’m looking for is:
([1,2,3],[1,1,4],[2,2,2])
To map these equally, I use a map function as follows:
@grouping = map { int( ($items + $_) / $groups ) } 0 .. $groups-1;
To get all combinations I’m thinking some kind of recursive function where each level of recursion N finds the possible values for element N in the array. The eligible values each level can insert is >= previousLevel. This is sort of what I’m thinking but there has got to be a better way to do this….
sub getList($$@){
my $itemCount = shift;
my $groupCount = shift;
my @currentArray = @_;
my $positionToFill= @currentArray;
if($positionToFill == 0){
my $minValue = 1;
}
else{
my $minValue = currentArray[$positionToFill-1];
}
my $currentSum = sum(@currentArray);
return undef if $currentSum + $minValue >= $items;
my @possibleCombinations = ();
for(my $i = $minValue; $i < $items - $currentSum; $i++){
$currentArray[$positionToFill] = $i;
if($positionToFill == $groupCount-1){
push(@possibleCombinations, \@currentArray)
}
else{
push(@possibleCombinations, getList($itemCount, $groupCount, @currentArray);
}
}
return @currentArray;
}
To group N items into M groups, ultimately you need a recursive function that groups N-1 (or fewer) items into M-1 groups.
and start the process with a call like
This method will produce a few duplicates that you’ll have to filter out, but overall it will be pretty efficient.