题目描述
一个正整数 n 可以表示成若干个正整数之和,形如:n=n1+n2+…+nk,其中 n1≥n2≥…≥nk,k≥1。
我们将这样的一种表示称为正整数 n 的一种划分。
现在给定一个正整数 n,请你求出 n 共有多少种不同的划分方法。
样例
输入样例:
5
输出样例:
7
算法一
这个问题可以转换为完全背包问题,1~i中任意一个数可以选无限次等价于,1~i个物品任意一个物品可以选无限次
#include<iostream>
using namespace std;
const int N=1010,mod=1e9+7;
int f[N][N];
int main()
{
int n;
cin>>n;
for(int i=0;i<=n;i++)f[i][0]=1;//注意初始化从前i个物品里面选,总和为0的选法为1
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=0;k<=j/i;k++)
f[i][j]=(f[i][j]+f[i-1][j-k*i])%mod;
cout<<f[n][n]<<endl;
return 0;
}
根据完全背包的优化
f[i][j]=f[i-1][j],f[i-1][j-i]......f[i-1][j-k*i]
f[i][j-i]= ,f[i-1][j-i]......f[i-1][j-k*i]
#include<iostream>
using namespace std;
const int N=1010,mod=1e9+7;
int f[N][N];
int main()
{
int n;
cin>>n;
for(int i=0;i<=n;i++)f[i][0]=1;//注意初始化从前i个物品里面选,总和为0的选法为1
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
f[i][j]=f[i-1][j]%mod;
if(j>=i)f[i][j]=(f[i][j]+f[i][j-i])%mod;
}
cout<<f[n][n]<<endl;
return 0;
}
#include<iostream>
using namespace std;
const int N=1010,mod=1e9+7;
int f[N];
int main()
{
int n;
cin>>n;
f[0]=1;//从前0个物品里面,总和为0选法为1
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
f[j]=(f[j]+f[j-i])%mod;
cout<<f[n]<<endl;
return 0;
}
算法二
#include<iostream>
using namespace std;
const int N=1010,mod=1e9+7;
int f[N][N];
int main()
{
int n;
cin>>n;
f[0][0]=1;//总和是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;//枚举总和是n,个是i
cout<<res<<endl;
return 0;
}