The problem is the following:
We have a number of months to buy a number of supplies. The sooner we finish buying them, the better, but we don't know how much we can buy per month and would like to calculate all possible scenarios.
Suppose months = 5 and supplies = 9, and (72000) means 7 in the first month, 2 in the second and 0 in the following months.
VALID: (90000) VALID: (81000) VALID: (72000) VALID: (71100) INVALID: (61200) INVALID: (80100)
This is basically a problem of combinations following a rule: in a MONTHS
sized array, the n-th element cannot be larger than the (n-1)-th element, and the sum of all elements must be SUPPLIES
.
My solution to do this was slicing the array into smaller parts and carrying digits over:
var months = 5;
var supplies = 9;
function calc(sum, nslots, maxdigit){
if (sum === 0) return [];
if (nslots === 0) return [];
maxdigit = maxdigit || sum;
var results = [];
var firstDigit = Math.min(maxdigit,sum);
if (maxdigit >= sum){
var digits = [];
for(var i=0;i<nslots;i++) digits.push(0);
digits[0] = firstDigit;
results = [digits];
}
for(;firstDigit>0;firstDigit--){
var pointsLeft = sum - firstDigit;
if (pointsLeft === 0) continue;
var subArrays = calc(pointsLeft, nslots-1, firstDigit);
if (subArrays.length === 0) continue;
var subResults = subArrays.map(function(i){return [firstDigit].concat(i);});
results = results.concat(subResults);
}
return results;
}
var results = calc(supplies,months);
console.log(results);
It's not in any way clear what this does though, and I myself would probably have a hard time understanding this code a year from now.
The clearest way I can imagine is just generating all numbers from 90000 down to 0 (in the 9 supplies and 5 months example) and checking if each number follows the rule, but it's ridiculous for bigger values of MONTHS
and SUPPLIES
.
I'd prefer a solution in ALGOL-descending languages. I imagine Python, Haskell or Erlang probably have some awesome way to solve this in just a few lines, but I couldn't use them here.