单点时限: 2.0 sec
内存限制: 256 MB
将正整数 n 表示成一系列正整数之和 : n=n1+n2+…+nk,其中 n1≥n2≥…≥nk≥1(k≥1)
正整数 n 的这种表示称为正整数 n 的拆分。求正整数 n 的不同拆分个数。
例如,正整数 6 有如下 11 种不同的拆分 :
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。
例如,正整数 3 有如下 3 种不同的拆分 :
3;
2+1;
1+1+1。
输入格式
本题有多组测试数据,每组一行,每行有一个正整数 N(1<=N<=100)
输出格式
每组测试数据输出一行,表示有多少种拆分方法
样例
input
1
3
5
output
1
3
7
整数划分百度
一个数n可以看成背包容量为n的背包,f[n]由n个价值和花费分别为i 的物品,能装满背包的种类数,而每种物品的数量不限,正好是一个完全背包问题。
int f[1000];
memset(f,0,sizeof(f));
f[0]=1;//注意这里很重要
for(int i=1; i<=n; i++)
for(int j=i; j<=n; j++)
f[j]=f[j]+f[j-i];
根据n和m的关系,考虑下面几种情况:
(1)当n=1时,不论m的值为多少(m>0),只有一种划分,即{1};
(2)当m=1时,不论 的值为多少(n>0),只有一种划分,即{1,1,…1,1,1};
(3)当n=m时,根据划分中是否包含n,可以分为两种情况:
(a)划分中包含n的情况,只有一个,即{n};
(b)划分中不包含n的情况,这时划分中最大的数字也一定比n小,即n的所有(n-1)划分;
因此,f(n,n) = 1 + f(n, n - 1)。
(4)当n<m时,由于划分中不可能出现负数,因此就相当于f(n,n);
(5)当n>m时,根据划分中是否包含m,可以分为两种情况:
(a)划分中包含 的情况,即{m,{x1,x2,x3,…,xi}},其中{x1,x2,x3,…,xi}的和为n-m,可能再次出现m,因此是(n-m)的m划分,因此这种划分个数为f(n-m,m;
(b)划分中不包含m的情况,则划分中所有值都比m小,即n的(m-1)划分,个数为f(n,m-1;
因此,f(n,m)=f(n-m,m)+f(n,m-1) 。
综合以上各种情况,可以看出,上面的结论具有递归定义的特征,其中(1)和(2)属于回归条件,(3)和(4)属于特殊情况,而情况(5)为通用情况,属于递归的方法,其本质主要是通过减少n或m以达到回归条件,从而解决问题。
详细递推公式描述如下:
#include<iostream>
using namespace std;
int main()
{
int n;
int dp[109][109];
for(int i = 1; i < 109; i++)
dp[i][1]=dp[1][i]=1;
for(int i = 2; i < 109; i++)
{
for(int j = 2; j < 109; j++)
{
if(i<j)
dp[i][j]=dp[i][i];
else if(i==j)
dp[i][j]=1+dp[i][j-1];
else
dp[i][j]=dp[i][j-1]+dp[i-j][j];
}
}
while(scanf("%d",&n)!=EOF)
{
cout<<dp[n][n]<<endl;
}
return 0;
}