整数划分
1、问题描述
将一个正整数 n 写成如下形式
n = m1 + m2 + ... + mi; (其中 mi 为正整数,并且 1 <= mi <= n),则 {m1, m2, ..., mi} 为 n 的一个划分。
如果 { m1, m2, ..., mi } 中的最大值不超过 m,即 max(m1, m2, ..., mi) <= m,则称它属于 n 的一个 m 划分。
算法分析
这里记 n 的 m 划分的个数为 f(n, m); 例如当 n = 4 时,有 5 个划分 {4}, {3,1}, {2,2}, {2,1,1}, {1,1,1,1};
该问题是求出 n 的所有划分个数,即 f(n, n)。下面考虑求 f(n,m) 的方法。
①、m = 1 || n = 1 只有一种划分情况,即 n 个 1 相加, 所以 f(n, m) = 1;
②、m = n > 1 f(n, m) = f(n, n-1) + 1 加上的 1 代表 n + 0 = n 这个划分方案
③、n < m f(n, m) = f(n, n) 逻辑上不存在 m > n 的情况
④、n > m f(n, m) = f(n, m-1) + f(n-m, m);
f(n, m-1) 表示划分方案中没有 m 的情况,f(n-m, m) 表示划分方案中有 m 的情况。
3、代码实现
#include <stdio.h>
/**
* @brief 整数划分问题,将一个整数划分为若干个数相加。例:整数 4,最大加数 4
4 =4 + 0
1+3=4
1+1+2=4
2+2=4
1+1+1+1=4
注意:1+3=4,3+1=4被认为是同一种划分方案
* @param n 需要划分的数字
* @param m 最大的加数
*/
int algorithm(int n, int m)
{
if (n == 1 || m == 1) { // 只要存在一个为 1,那么划分的方法数肯定只有一种,那就是 n 个 1 相加
return 1;
}
else if (n == m && n > 1) { // 等价于:q(n, n-1) + 1; 最后面 +1 代表的是:0+n,这个划分的方案
return algorithm(n, m - 1) + 1;
}
else if (n < m) { // 如果 m > n,那么令 m = n,因为最大加数在逻辑上不可能超过 n
return algorithm(n, n);
}
else if (n > m) { // 分为两种:划分方案没有 m 的情况 + 划分方案有 m 的情况
return algorithm(n, m - 1) + algorithm(n - m, m);
}
return 0;
}
int main()
{
int r = algorithm(7, 7);
printf("%d\n", r);
return 0;
}