Раз там дискретно, целыми, то можно по одному литру раскладывать в цикле.
Для массива посчитать «спрос» – сколько в идеале там должно быть (дробные числа).
И на каждой итерации определять самый обездоленный, далёкий от своего идеала, элемент массива – туда класть очередной литр.
function spread(q, volumes) {
const total = volumes.reduce((a, b) => a + b);
const result = volumes.slice().fill(0);
const target = volumes.map((v) => q * v / total);
while (q--) {
const demand = result.map((v, i) => target[i] - v);
const minIndex = demand.indexOf(Math.max(...demand));
result[minIndex]++;
}
return result;
}
spread(4, [1, 10, 3]) // [0, 3, 1]
spread(9, [1, 10, 3]) // [1, 6, 2]
spread(1, [10, 10, 10]) // [1, 0, 0] - слева направо при равных
spread(33, [10, 10, 10]) // [11, 11, 11] - переполняются тоже одинаково
spread(4, [2, 3, 1]) // [ 1, 2, 1 ]
spread(5, [2, 3, 1]) // [ 2, 2, 1 ]
spread(9, [2, 3, 1]) // [ 3, 5, 1 ]