有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。
第 i 件物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出 最优选法的方案数。注意答案可能很大,请输出答案模 109+7 的结果。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。
接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。
输出格式
输出一个整数,表示 方案数 模 109+7 的结果。
数据范围
0<N,V≤1000 0<vi,wi≤1000
输入样例
4 5
1 2
2 4
3 4
4 6
输出样例:
2
思路
用 g 数组记录当前 状态 的最大方案数
显然在f[i][j]
转移时有两个方向:
f[i - 1][j]
和 f[i - 1][j - v[i]] + w[i]
若这两个不相等说明选择了其中一个方案, 若相同则将两个的方案数都加一起。
代码
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
const int N = 1e3 + 10, mod = 1e9 + 7;
int f[N];
int g[N];
int w[N],v[N];
int n,m;
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i++)
cin >> v[i] >> w[i];
g[0] = 1;
for(int i = 1; i <= n; i++)
{
for(int j = m; j >= v[i]; j--)
{
int maxv = max(f[j - v[i]] + w[i], f[j]);
int cnt = 0;
if(maxv == f[j - v[i]] + w[i]) cnt = g[j - v[i]];
if(maxv == f[j]) cnt = (cnt + g[j]) % mod;
f[j] = maxv;
g[j] = cnt;
}
}
int cnt = g[m];
for(int i = 0; i < m; i++)
if(f[m] == f[i])
cnt = (cnt + g[i]) % mod;
//cout << f[n][m] << endl;
cout << cnt << endl;
return 0;
}