法1:将此问题变为容量为n的完全背包问题,有质量分别为1,2,3,,,n的物品,每个物品有无穷多件,问能装满这个背包的方法有多少种?
任何一种等式都可以看做是背包问题。
f[i][j] 表示的是从1 - i个物品中选物品,体积恰好是j的选择种数
按照这个思路写出状态转移方程是
这里进行了优化,将s次计算变为了一次
这里为了节约内存空间,将二维转换为1维,这里把第一维选择了几个物品省略掉了。题目要求的是选择任意多个物品,达到指定体积就可以。因此用一维数组时只需从小到大枚举即可。
#include<iostream>
using namespace std;
const int N = 1010, mod = 1e9 + 7;
int f[N];
int n;
int main(){
cin >> n;
//初始化,只有f[0][0] = 1, 其余f[i][0]都为0
f[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;
}
法2:
f[i][j] = f[i - 1][j - 1] + f[i - j][j];
f[i - 1][j - 1] 表示的集合是最小值是1, 因此将最小值1减出去
f[i - j][j] 表示所有值的最小值都大于1,那么将每个值都减去1,就得到了该表达式
#include<iostream>
using namespace std;
const int N = 1010, mod = 1e9 + 7;
int f[N][N];
int n;
int main(){
cin >> n;
//初始化,只有f[0][0] = 1, 其余f[i][0]都为0
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 j = 1; j <= n ;j++){
res = (res + f[n][j]) % mod;
}
cout << res << endl;
return 0;
}