一、概述
n = n1 + n2 + n3 +++ nk n1>=n2>=n3 >=nk >= 1;
正整数n的这种表示称为正整数n的划分。求正整数n的不同划分个数。
这是一道递归经典问题,将正整数表示成一系列整数之和。
二、思路
例如 5 可以划分为:
- (5)
- (4,1)、(3,2)
- (3,1,1)、(2,2,1)
- (2,1,1,1)
- (1,1,1,1,1)
总共 7 种可能。
建立 q(n, m) n 为正整数的划分, m 为其中最大的加数。
接下来就是分类讨论的时光了
- n = 1 时,m 无论为何值,只有一种分法 「1」
- m = 1 时, n 无论为何值,只有一种分法 (1+1+1 +++ 1) 总共有 n 个 1 在加。
- n < m 最大的加数比 n 还大 则变为 q(n,n)。
- n == m 时
- 当分法中包含 m 时 只有一种分法(m)
- 当分法不包含 m 时 我们刚开始说 m 是加数 现在分法中不包含 m 所以最大的加数现在是 m-1,则 q(n,n) = 1 + q(n,n-1)。
- n > m 时
- 当分法中包含 m 时 (m,n1 + n2 + + nk) n1加到nk的值就是n-m 递归就是子问题与原问题一样只是范围一样 则 q(n-m,m)划分的数变成n-m 最大加数还是m
- 当分法中不包含m时最大加数变为m-1
可知,当 n 大于 m 时, q(n,m) = q(n-m,m) + q(n,m-1)
由前面的所有情况可知:
q(n, m)
- n = 1 或者 m = 1 结果为 1
- n < m 结果为 q(n, n)
- n = m 结果为 q(n, n - 1) + 1
- n > m 结果为 q(n - m,m) + q(n,m - 1)
三、代码
int q(int n, m)
{
if(n < 1 || m < 1)
return 0;
if(n == 1 || m == 1)
return 1;
if(n < m)
return q(n, n);
if(n == m)
return q(n,n-1) + 1;
return q(n-m,m) + q(n, m-1);//最后一种情况
}