题目描述:
整数划分问题是将一个正整数n拆成一组数连加并等于n的形式,且这组数中的最大加数不大于n。
即:n=n1+n2+…+nk;
n1>=n2>=n3…>=nk
如整数的6划分为:
6
5 + 1
4 + 2, 4 + 1 + 1
3 + 3, 3 + 2 + 1, 3 + 1 + 1 + 1
2 + 2 + 2, 2 + 2 + 1 + 1, 2 + 1 + 1 + 1 + 1
1 + 1 + 1 + 1 + 1 + 1共11种。
补充:正整数的这种操作称为正整数的划分,正整数的不同划分个数称为正整数n的划分数,记为p(n)。例如:p(6)=11;
解题:
分析:在如上对6的划分中,我们可以发现分层进行。将最大加数不超过m的划分个数记作q(n,m).
p(6)=q(6,6)
对q(n,m),我们可以建立如下递归关系。
(1).q(n,1)=1,n>=1;
即n只能划分为1+1+…+1(n个1️⃣)
(2).q(n,m)=q(n,n),m>=n;
最大加数m永远不能大于n。
(3)q(n,n)=1+q(n,n-1)。
当取n1=n时,只有一种划分,当n1=n-1时,有q(n,n-1)种划分
(4):q(n,m)=q(n,n-1)+q(n-m,m),n>m>1.
(正整数n的最大加数n1不大于m的划分)即q(n,m)由n1=m的划分(这里可看做q(n-m,m),因为第一个数确定为m,剩下数的总和为n-m,对其在拆分即可)和n1<=m-1的划分组成。
综上:得到q(n,m)的递归式
q(n,m)={1,n=1,m=1;
------------q(n,n),n<m;
------------q(n,n-1)+1,n=m
------------q(n,m-1)+q(n-m,m),n>m>1}
代码实现:C++
#include<iostream>
using namespace std;
int q(int n,int 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, m - 1) + 1;
return q(n, m - 1) + q(n - m, m);
}
int main() {
int n;
cin >> n;
cout << q(n, n) << endl;
return 0;
}
代码实现,JAVA:
public static int q(int n,int 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, m - 1) + 1;
return q(n, m - 1) + q(n - m, m);
}
效果:
总结:这是最经典的分治之一,反复应用分治手段,可以使子问题和原问题类型一致而规模不断缩小,最终使得子问题很容易求解,最后合并所得解即可。本题中,通过对q(n,n)的分解,我们得到若干个简单的子问题q(6,1)、q(1,5)等等,最终合并得p(n).