查找总和数的多少组合(代码中的变量 n )。例如:
3 = 1 + 1 + 1 = 2 + 1 = 3 => ANS是3
5 = 5 = 4 + 1 = 3 + 2 = 3 + 1 + 1 = 2 + 2 + 1 = 2 + 1 + 1 + 1 = 1 + 1 + 1 + 1 + 1 => ANS是7
在以下示例中, m 是最大数字,n
是总和,
目的是找出它有多少(总和)组合。
我只是想知道为什么p(n, m) = p(n, m - 1) + p(n - m, m)
?
这里的代码:
int p (int n, int m)
{
if (n == m)
return 1 + p(n, m - 1);
if (m == 0 || n < 0)
return 0;
if (n == 0 || m == 1)
return 1;
return p(n, m - 1) + p(n - m, m);
}
赞赏!
答案 0 :(得分:21)
通过添加小于或等于n
的某些数字,考虑所有生成m
的方法。如你所说,我们称之为p(n,m)
。例如,p(7,3)= 8,因为有8种方法可以使7个数字小于3,如下所示:(为简单起见,我们可以假设始终按照从最大到最小的顺序添加数字)
现在我们可以将这些组合分成两组:
第一个元素等于m
的组合(在我们的示例中= 3)
第一个元素小于m
的组合:
因为p(n,m)
组合的每个成员都在Group1或Group2中,我们可以说p(n,m)=size(Group1) + size(Group2)
。现在,如果我们通过替换证明size(Group1)=p(n-m, m)
和size(Group2)=p(n,m-1)
,我们就会达到p(n,m)=p(n-m,m)+p(n,m-1)
size(Group1)=p(n-m, m)
:按照上述定义,p(n-m, m)
是通过添加小于或等于n-m
的某些数字来生成m
的方式的数量。
m
附加到p(n-m, m)
的每个组合,则会产生Group1的成员。所以p(n-m, m) <= size(Group1)
m
,则会产生p(n-m, m)
的组合。所以size(Group1) <= p(n-m, m)
=> size(Group1) = p(n-m, m)
。在我们的例子中:
组1&lt; ===对应===&gt; p(4,3):
3+1
&lt; ===========&gt; 3+1
= 4 2+2
&lt; ===========&gt; 2+2
= 4 2+1+1
&lt; =======&gt; 2+1+1
= 4 1+1+1+1
&lt; ===&gt; 1+1+1+1
= 4 因此p(n-m,m)
的任何成员与Group1之间存在一对一的对应关系,且其大小相等。
size(Group2)=p(n, m-1)
:根据定义,p(n,m-1)
是通过添加小于或等于n
(小于m-1
)的某些数字来获得m
的结果的数量。如果您重新阅读Group2的定义,您将看到这两个定义彼此相同。 => size(Group2) = p(n, m-1)
答案 1 :(得分:4)
首先,您需要了解此功能,请参阅http://mathworld.wolfram.com/PartitionFunctionP.html。
对于此公式,请记住p(n, m)
被定义为最大成员最多n
的{{1}}分区数。
因此m
是p(n, m)
的分区数,其最大成员最多为m
。让我们根据最大成员实际是m
来划分它们。
最大成员为m
的分区数是填充m
的方式数,n = m + ...
是最大成员最多n-m
的{{1}}分区数根据定义,m
。
p(n-m, m)
的最大成员最多n
的分区数量定义为m-1
。
因此p(n, m-1)
。
答案 2 :(得分:3)
/ 0 (k>n)
p(k,n)={ 1 (k=n)
\ p(k+1,n)+p(k,n-k) (k<n)
n的分区数是p(1,n)。
p(k,n)是n的分区数, 只允许加数&gt; = k。
与OP的递归公式一样,它逐个添加它们(如luiges90所示)(增加了许多零的低效率)。幸运的是,它可以在数组内以极快的速度计算:
#include <stdio.h>
/* 406 is the largest n for which p(n) fits in 64 bits */
#define MAX 406
long long int pArray[MAX][MAX];
/* Emulate array starting at 1: */
#define p(k,n) pArray[k-1][n-1]
int main(int argc, char **argv) {
int n, k;
for (n = 1; n < MAX; n++) {
for (k = n; k > 0; k--) {
if (k > n) {
p(k, n) = 0;
}
else if (k == n) {
p(k, n) = 1;
}
else {
p(k, n) = p(k, n-k)+p(k+1, n);
}
}
}
for (n = 1; n < MAX; n++) {
printf("p(%d)=%lld\n", n, p(1,n));
}
}
答案 3 :(得分:2)
将p(n, m)
表示为总和为n
且每个加数小于或等于m
的所有组合的数量。这里的关键是证明以下递归方程:
p(n, m) - p(n, m - 1) = p(n-m, m) (1)
(1)的左边是p(n,m)和p(n,m - 1)的差值,它是包含至少一个m
作为加数的所有组合的数量,剩余的总和为n-m
(总体为n
),除了每个加数小于或等于m
。但这恰恰意味着p(n-m,m),这是(1)的右侧。
显然,问题的答案应该是p(n,n)。