В связи со значительным прогрессом в программировании вычисления количества разбиений (partitions) целого числа
10. Сколько существует способов разложить
![$n$ $n$](https://dxdy-02.korotkov.co.uk/f/5/5/a/55a049b8f161ae7cfeb0197d75aff96782.png)
одинаковых шаров в
![$k$ $k$](https://dxdy-03.korotkov.co.uk/f/6/3/b/63bb9849783d01d91403bc9a5fea12a282.png)
одинаковых урн?
Код:
N10(n,k)=#partitions(n,,[1,k])
Этот способ лаконичный, но для больших аргументов медленный или невыполнимый - т.к. создаётся массив разбиений, объем которого может быть очень велик, после чего подсчитывается количество элементов массива.
Следующие две функции подсчитывают требуемое количество намного быстрее и потребляют меньше памяти.
10.1 "Прямой" подсчет по рекуррентной формуле
![$P(0,0)=1;P(n>1,0)=0;P(n,k)=P(n,k-1)+P(n-k,k)$ $P(0,0)=1;P(n>1,0)=0;P(n,k)=P(n,k-1)+P(n-k,k)$](https://dxdy-03.korotkov.co.uk/f/2/5/a/25a34636f9d39075e6f6b7b7e9007c9c82.png)
с запоминанием промежуточных результатов. Для больших аргументов переполняется массив в котором запоминаются предыдущие вычисления.
(Оффтоп)
Код:
N10_1(n,k)=
{
local(M = Map());
my(memo_p = (N,K)-> my(res);
if(N==0 && K==0,
return(1));
if(K<1,
return(0));
if(mapisdefined(M,[N,K],&res),
return(res));
if(K>=N,
res=numbpart(N);
mapput(M,[N,K],res);
return(res));
res=self()(N,K-1)+self()(N-K,K);
mapput(M,[N,K],res);
return(res));
memo_p(n,k);
}
10.2. "Хитрый" подсчет созданием матрицы размером
[k+1] x [k] и последовательным вычислением, требует примерно n x k вычислений. Позаимствован в списке рассылки пользователей pari/gp у Karim Belabas (
http://pari.math.u-bordeaux.fr/archives ... 00015.html ) Промежуточная структура тоже может быть очень большой, но скорее ограничение тут по скорости работы:
(Оффтоп)
Код:
N10_2(n,k) =
{
my(k1 = k+1, kx = k1, a = 1, t = vector(k1, i, vector(k)));
t[k1][1] = 1;
for (i = 1, n-1,
my(ky = a);
t[a] = vector(k, j, if (!(ky--), ky = k1);
if (j == 1, t[ky][1]
, t[kx][j-1] + t[ky][j]));
kx = a; if (a++ > k1, a = 1));
vecsum(t[a-1]);
}
Сравнительная скорость вычислений:
(Оффтоп)
? N10(70,30)
time = 203 ms.
%1 = 3910071
? N10_1(70,30)
time = 31 ms.
%2 = 3910071
? N10_2(70,30)
%3 = 3910071
? ##
*** last result computed in 0 ms.
Берем значения побольше. Первый метод -- не хватает памяти.
Два других:
? N10_1(1000,300)
time = 2,637 ms.
%4 = 24060233693068843871790330541103
? N10_2(1000,300)
time = 172 ms.
%5 = 24060233693068843871790330541103
? N10_2(10000,3000)
time = 28,407 ms.
%6 = 36167251325636291851786878829976856243927867494801874150751474019863050338273687745917678081066889663513003
11. Сколько существует способов разложить
![$n$ $n$](https://dxdy-02.korotkov.co.uk/f/5/5/a/55a049b8f161ae7cfeb0197d75aff96782.png)
одинаковых шаров в
![$k$ $k$](https://dxdy-03.korotkov.co.uk/f/6/3/b/63bb9849783d01d91403bc9a5fea12a282.png)
одинаковых урн так, чтобы в каждой урне было не более одного шара (при условии
![$k\ge n$ $k\ge n$](https://dxdy-04.korotkov.co.uk/f/f/e/8/fe87199173ef9b635e50d20613f8486682.png)
)?
Код:
N11(n,k)=if(k>=n,return(1),return(0))
12. Сколько существует способов разложить n одинаковых шаров в k одинаковых урн так, чтобы в каждой урне было не менее одного шара (при условии
![$n\ge k$ $n\ge k$](https://dxdy-04.korotkov.co.uk/f/7/4/3/743c3e2b9c81cbfdaeb016c6b96d99ba82.png)
)?
Код:
N12(n,k)=#partitions(n,,[k,k])
Замечания те же что и для задачи 10, так что только привожу "быстрый" код для решения:
(Оффтоп)
Код:
N12_2(n,k)=
{
my(k1 = k+1, kx = k1, a = 1, t = vector(k1, i, vector(k)));
t[k1][1] = 1;
for (i = 1, n-k-1,
my(ky = a);
t[a] = vector(k, j, if (!(ky--), ky = k1);
if (j == 1, t[ky][1]
, t[kx][j-1] + t[ky][j]));
kx = a; if (a++ > k1, a = 1));
vecsum(t[a-1]);
}