Skip to content

Instantly share code, notes, and snippets.

@sergiks
Created March 30, 2020 17:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sergiks/db7fed64fa0be68bfcf134c8a167a771 to your computer and use it in GitHub Desktop.
Save sergiks/db7fed64fa0be68bfcf134c8a167a771 to your computer and use it in GitHub Desktop.

N random numbers that add to a fixed sum

Given a sum, break it into n random numbers. (sum, n) => [x1, x2, ... xn] // so that: // x1 + x2 + ... + xn = sum // x1 > x2 > ... > xn > 0

Разбить данное число на N случайных слагаемых

Так, что слагаемые одно больше другого (без равных).

Для вопроса на QnA Habr com

Решение

x          = k0 
y = x + k1 = k0 + k1
z = y + k2 = k0 + k1 + k2
m = z + k3 = k0 + k1 + k2 + k3
-----------------------------
x+y+z+m    = 4k0 + 3k1 + 2k2 + k3 = SUM

ki это натуральные числа от 1

Найдём k0 Т.к. на k1..k3 уходит минимум 6, когда все по 1, для k0 остаётся диапазон от 1 до (SUM - 6) / 4

Выбрав случайный k0 в этом диапазоне, получаем новую целевую сумму SUM1, которую нужно заполнить 3k1 + 2k2 + k3 = SUM1

Рекурсия. Но на последнем шаге k3 это весь остаток.

const addUpTo = (top, n) => {
const getDiffs = (sum, n, acc = []) => {
if (n === 1) {
x = sum;
} else {
const headroom = (n - 1) * n / 2;
const cap = Math.floor((sum - headroom) / n);
if (cap < 1) throw("Impossible. " + JSON.stringify(acc));
x = 1 + Math.floor(Math.random() * cap);
}
acc.push(x);
if (n <= 1) {
return acc;
} else {
return getDiffs(sum - x * n, n - 1, acc);
}
}
return getDiffs(top, n).map((_, i, a) => a.reduce((acc, c, j) => j <= i ? acc + c : acc)).reverse();
}
addUpTo(100, 4)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment