Если вы хотите знать количество способов , чтобы сделать это, тогда вы можете использовать генерирующие функции.
По сути, вы заинтересованы в целочисленных разбиениях .Целочисленное разбиение X
- это способ записать X
в виде суммы натуральных чисел.Пусть p(n)
будет числом целочисленных разбиений n
.Например, если n=5
, то p(n)=7
соответствует разделам:
5
4,1
3,2
3,1,1
2,2,1
2,1,1,1
1,1,1,1,1
Функция генерации для p(n)
равна
sum_{n >= 0} p(n) z^n = Prod_{i >= 1} ( 1 / (1 - z^i) )
Чтоэто вам подходит? Расширив правую сторону и взяв коэффициент z^n
, вы можете восстановить p(n)
.Не беспокойтесь, что продукт бесконечен, поскольку для вычисления p(n)
вам понадобится только конечное число терминов.На самом деле, если это все, что вам нужно, просто обрежьте продукт и остановитесь на i=n
.
Почему это работает? Помните, что
1 / (1 - z^i) = 1 + z^i + z^{2i} + z^{3i} + ...
Итак, коэффициент z^n
- это количество способов записи
n = 1 * a_1 + 2 * a_2 + 3 * a_3 + ...
где сейчасЯ имею в виду a_i
как число раз, которое i
появляется в разделе n
.
Как это обобщается? Легко,как выясняется.Из приведенного выше описания, если вы хотите, чтобы только части раздела были в заданном наборе A
, то вместо того, чтобы брать продукт за все i >= 1
, принимайте продукт только за i in A
.Пусть p_A(n)
будет числом целочисленных разделов n
, чьи части взяты из набора A
.Тогда
sum_{n >= 0} p_A(n) z^n = Prod_{i in A} ( 1 / (1 - z^i) )
Опять же, взяв коэффициент z^n
в этом расширении, вы решите вашу проблему.Но мы можем пойти дальше и отследить количество частей раздела.Для этого добавьте еще один заполнитель q
, чтобы отслеживать, сколько деталей мы используем.Пусть p_A(n,k)
будет числом целочисленных разбиений n
на k
частей, где части происходят из набора A
.Затем
sum_{n >= 0} sum_{k >= 0} p_A(n,k) q^k z^n = Prod_{i in A} ( 1 / (1 - q*z^i) )
, поэтому, принимая коэффициент q^k z^n
, мы получим количество целочисленных разбиений n
на k
частей, откуда эти элементы поступают из набора A
.
Как вы можете закодировать это? Подход с использованием функции генерации фактически дает вам алгоритм для генерации всех решений проблемы, а также способ единообразной выборки из набора решений.После выбора n
и k
произведение справа будет конечным.