递归函数的声明为int split(int n, int m),其中n为要划分的正整数,m是划分中最大的正整数。
4 = 4;
4 = 3 + 1;
4 = 2 + 2;
4 = 2 + 1 + 1;
4 = 1 + 1 + 1 + 1;
5=5;
5=4+1;
5=3+2;
5=3+1+1;
5=2+2+1;
5=2+1+1+1;
5=1+1+1+1+1;
算法的基本思想如下:
将计算过的值存储在备忘录(数组)中,下次使用时直接调用,不再重复计算;
当n=0或者m=0时,存储0并返回;(因为没有存在划分的整数或最大划分值为0)
当n=1或者m=1时,存储1并返回;(因为如果划分的整数或最大划分值是1,那么只有一种情况,要么只有一个1不用划分,要么就是用1来划分整数就是n个1只有一种情况)
当m>n时,存储split(n,n)并返回;(因为需要划分整数的最大正整数不能超过n)
当m==n时,只有n自身包含m,存储split(n,m-1)+1并返回;(如果两个值相等,那么就是把自身等于自身的情况去掉算一种+1)
当m<n时,分为分解包含m和不包含m两种情况,存储split(n,m-1)+split(n-m,m)并返回。(这个就是把从前面的递归是递归例子的(<m)下面的情况,后面的递归是递归上面的数量)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int a[125][125];
int dp(int n,int m){
if (a[n][m] > )0){
return a[n][m];
}
else if(m==0||n==0){
return a[n][m]=0;
}
else if(n==1||m==1){
return a[n][m]=1;
}
else if(n==m){
return a[n][m]=dp(n,m-1)+1;
}
else if(n<m){
return a[n][m]=dp(n,n);
}
else if(n>m){
return a[n][m]=dp(n,m-1)+dp(n-m,m);
}
}
int main(int argc, char** argv) {
int n;
while(cin>>n){
memset(a,0,sizeof(a));
cout<<dp(n,n)<<endl;
}
return 0;
}
这种方法我就有个疑问为什么要加一个if (a[n][m] > 0){return a[n][m];}不加还过不去。我更倾向于第二种的数组解决的方法
先计算出所有子问题的解,然后查找即可。这种算法的AC代码如下:(其实我感觉这个跟上面的一样只是用数组代替了dp()更加简洁,比较容易想明白)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int a[125][125];
int main(int argc, char** argv) {
int n;
memset(a,0,sizeof(a));
for(int i=0;i<=120;i++){
a[0][i]=0;
a[i][0]=0;
}
for(int j=1;j<=120;j++){
a[1][j]=1;
a[j][1]=1;
}
for(int i=2;i<=120;i++){
for(int j=2;j<=120;j++){
if(i==j){
a[i][j]=a[i][j-1]+1;
}
else if(i<j){
a[i][j]=a[i][i];
}else {
a[i][j]=a[i][j-1]+a[i-j][j];
}
}
}
while(cin>>n){
cout<<a[n][n]<<endl;
}
return 0;
}