一个正整数 n可以表示成若干个正整数之和,形如:n=n1+n2+…+nk,其中 n1≥n2≥…≥nk,k≥1
我们将这样的一种表示称为正整数 n 的一种划分。
现在给定一个正整数 n,请你求出 n共有多少种不同的划分方法。
输入格式
共一行,包含一个整数 n。
输出格式
共一行,包含一个整数,表示总划分数量。
由于答案可能很大,输出结果请对 10^9+7 取模。
数据范围
1≤n≤1000
输入样例:
5
输出样例:
7
完全背包做法:
根据y总的思路,f [i] [j]=f [i-1] [j]+f [i-1] [j-i]+f [i-1] [j-2*i]+……+f[i-1] [j-s*i] //s*i<j;
并且 f [i] [j-i]= f [i-1] [j-i]+f [i-1] [j-2*i] +……+f[i-1] [j-s*i]
合并则为f [i][j]=f [i-1] [j] + f [i-1] [j-i]
简化为一维的状态转移方程就是 f [ j ] =f [ j ] +f [ j - i ];
那么代码如下:
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010,mod=1e9+7;
int n;
int dp[N];
int main()
{
scanf("%d",&n);
dp[0]=1;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
dp[j]=(dp[j]+dp[j-i])%mod;
printf("%d",dp[n]);
return 0;
}
另外一种做法是将状态分为划分的数最小值是1,和最小值不是1 两类。
实现代码如下
#include<iostream>
using namespace std;
const int N=1010,mod=1e9+7;
int n;
int f[N][N];
int main()
{
cin>>n;
f[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
f[i][j]=(f[i-1][j-1]+f[i-j][j])%mod;
int res=0;
for(int i=1;i<=n;i++) res=(res+f[n][i])%mod;
cout<<res<<endl;
return 0;
}