有 NNN 件物品和一个容量是 VVV 的背包。每件物品只能使用一次。
第 iii 件物品的体积是 viv_ivi,价值是 wiw_iwi。求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出 最优选法的方案数。注意答案可能很大,请输出答案模 109+710^9+7109+7 的结果。
输入格式
第一行两个整数,N,VN,VN,V,用空格隔开,分别表示物品数量和背包容积。
接下来有 NNN 行,每行两个整数 vi,wiv_i,w_ivi,wi,用空格隔开,分别表示第 iii 件物品的体积和价值。
输出格式
输出一个整数,表示 方案数 模 109+710^9+7109+7 的结果。
数据范围
0<N,V≤10000<N,V≤10000<N,V≤1000
0<vi,wi≤10000<v_i,w_i≤10000<vi,wi≤1000
输入样例:
4 5
1 2
2 4
3 4
4 6
输出样例:
2
首先这个要求的是体积不超过 VVV 并且总价值最大的 方案数, 首先需要求出的就是总价值最大, 其次是方案数, 然后要让方案数 对应上总价值, 不同的体积对应不同的方案数, 所以方案数的状态要用体积恰好为 jjj 来表示, 而不能用不超过 jjj 来表示,然后因为方案数要与总价值相对应,所以总价值的状态也要用 体积恰好为 jjj 来表示.
状态表示 f[i][j]f[i][j]f[i][j] : 在前 iii 个物品中选,并且体积恰好为 jjj 的集合
状态属性: 总价值的最大值
状态计算: 选第 iii 个物品 和 不选第 iii 个物品
f[i][j]=max(f[i−1][j],f[i−1][j−v[i]]+w[i]);f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);f[i][j]=max(f[i−1][j],f[i−1][j−v[i]]+w[i]);
状态表示 cnt[i][j]cnt[i][j]cnt[i][j] : 在前 iii 个物品中选, 并且总体积恰好为 jjj 的集合
状态属性: 体积j对应的方案数
令 resresres 表示体积为 jjj 时的方案数
如果 max==f[i][j]max == f[i][j]max==f[i][j]
----> res+=cnt[i][j];res += cnt[i][j];res+=cnt[i][j];
如果 max==f[i][j−v]max == f[i][j - v]max==f[i][j−v]
-----> res+=cnt[i][j−v];res += cnt[i][j - v];res+=cnt[i][j−v];
最后更新 cnt[i][j]cnt[i][j]cnt[i][j]
-------> cnt[i][j]=rescnt[i][j] = rescnt[i][j]=res % mod;mod;mod;
#include<iostream>
#include<algorithm>
#include<cstring>
const int N = 1100, mod = 1e9 + 7;
int f[N], cnt[N], n, m;
using namespace std;
int main()
{
cin >> n >> m;
memset(f, - 0x3f, sizeof f); //因为这里是恰好体积为j,且求最大价值,所以需要初始化为负无穷
f[0] = 0; //当体积为0时, 价值初始化为0
cnt[0] = 1; // 当体积为0时, 即什么也不选时,也是一种方案
for(int i = 1; i <= n; i ++ )
{
int v, w;
cin >> v >> w;
int maxv = 0;
for(int j = m; j >= v; j -- ) //枚举体积
{
maxv = max(f[j], f[j - v] + w); //状态转移
int res = 0; //创建变量保存当前的方案数
if(maxv == f[j]) res += cnt[j]; //状态转移
if(maxv == f[j - v] + w) res += cnt[j - v]; //状态转移
cnt[j] = res % mod; //更新状态
f[j] = maxv; //更新状态
}
}
int res = 0;
for(int i = 0; i <= m; i ++ ) res = max(res, f[i]); //枚举体积,找到最大价值
int ans = 0;
//如果当前价值等于最大价值, 记录方案数
for(int i = 0; i <= m; i ++ ) if(res == f[i]) ans = ( ans + cnt[i] ) % mod;
cout << ans << '\n';
}
该博客探讨了如何使用动态规划解决0/1背包问题,寻找在不超过背包容量的情况下最大化物品价值的方案数。通过建立状态表示总价值最大和方案数,并进行状态转移,最终求得最大价值及对应的方案数。代码实现中涉及到了状态初始化、状态转移方程以及方案数的累加和更新。
384

被折叠的 条评论
为什么被折叠?



