题意
一个正整数 nn 可以表示成若干个正整数之和,形如:n=n1+n2+…+nk,其中 n1≥n2≥…≥nk,k≥1。
我们将这样的一种表示称为正整数 n 的一种划分。
现在给定一个正整数 nn,请你求出 n 共有多少种不同的划分方法。
输入格式
共一行,包含一个整数 n。
输出格式
共一行,包含一个整数,表示总划分数量。
由于答案可能很大,输出结果请对 109+7 取模。
数据范围
1≤n≤1000
输入样例:
5
输出样例:
7
思路
把1,2,3, … n分别看做n个物体的体积,这n个物体均无使用次数限制,问恰好能装满总体积为n的背包的总方案数(完全背包问题变形)
分析
优化分析
f[i][j] 表示前i个整数(1,2…,i)恰好拼成j的方案数
求方案数:把集合选0个i,1个i,2个i,…全部加起来
f[i][j] = f[i - 1][j] + f[i - 1][j - i] + f[i - 1][j - 2 * i] + ...;
f[i][j - i] = f[i - 1][j - i] + f[i - 1][j - 2 * i] + ...;
因此 f[i][j]=f[i−1][j]+f[i][j−i]; (这一步类似完全背包的推导)
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1010,MOD=1e9+7;
int dp[N][N];
int n;
int main() {
cin>>n;
for(int i=0;i<=n;i++){
dp[i][0]=1;//特殊地,dp[0][0]=1
}
for(int i=1;i<=n;i++){
for(int j=0;j<=n;j++){
dp[i][j]=dp[i-1][j]%MOD;
if(j-i>=0)
dp[i][j]=dp[i][j]+dp[i][j-i]%MOD;
}
}
cout<<dp[n][n];
return 0;
}
一维优化(类似完全背包)
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1010,MOD=1e9+7;
int dp[N];
int n;
int main() {
cin>>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;
}
}
cout<<dp[n];
return 0;
}