01 背包二维数组模板
PS: dp[300][300]定义在主函数外面,数组中的每个元素初始化为0,w存储每件物品重量,v存储每件物品的价值,只需每次外循环用到,所以无需使用数组存储,dp[i][j]表示背包容量为j时,从0-i个商品中任取所能获得的最大价值。
ps:原理类似一张表格,每次新增加一个物品,依次遍历不同容量的背包,如果发不下,就继承上一层的价值,如果放得下就比较上一层的价值和(不含这个物品i的剩余情况下的最大价值+物品i的价值)谁大就选哪一个,注意:下标,0-10,0-4分别表示容量为1,2,3,4…10的背包,1-4表示第1,2,3,4个物品,这是个不断遍历的过程
// 不使用数组存储每个商品的体积和价值
#include<bits/stdc++.h>
using namespace std;
int dp[300][300];
int main(){
int m,n; //m,n 输入的物品个数,背包容量
int w,v;
cout << w << v << '\n';
cin >> m >> n;
for(int i = 1;i<=m;i++){
cin >> w >> v;
for(int j =1;j<=n;j++){
j<w?dp[i][j] = dp[i-1][j]:dp[i][j] = max(dp[i-1][j],dp[i-1][j-w] + v);
}
}
cout << dp[m][n];
return 0;
}
01背包一维滚动数组优化模板
**PS:**dp[300]定义在主函数外面,默认每一个容量的背包大小的最大价值为0,数组尽量大一些,dp[j]表示背包容量为j时所能获得的最大价值。
ps:原理类似二维数组的解法,只是我们从最大的背包容量开始倒叙遍历,每一个物品也就是每一轮都会不断更新每一中容量背包的最大价值,直到更新完,我们只考虑背包容量>=新增物品体积的情况,这样我们每次都在覆盖dp[j]的值,只需要一维数组存储即可
// 不使用数组存储每个商品的体积和价值
#include<bits/stdc++.h>
using namespace std;
int dp[300];
int main(){
int m,n;
int w,v;
cin >> m >> n;
for(int i=1;i<=m;i++){
cin >> w >> v;
for(int j=n;j>=w;j--){
// 内层和i没关系了,这是一个重新赋值的过程,每次换一个物品都会更新一次状态
dp[j] = max(dp[j],dp[j - w] + v);
}
}
cout << dp[n];
}
// 使用数组存储每个商品的体积和价值
#include<bits/stdc++.h>
#include<iostream>
using namespace std;
// dp[j]表示容量为j的背包所能装下物品的最大价值,定义在主函数外面,里面的值默认为0
// ps: i和j从1开始,0背包和0物品不包括。
int w[300],v[300],dp[300];
int main()
{
int m,n; //分别表示物品个数和背包容量
cin >> m >> n;
for(int i = 1;i <= m;i++)
cin >> w[i] >> v[i]; //写入物品数据和背包容量数据
// 直接外循环(物品)+内循环(背包)
for(int i =1;i<=m;i++)
{ // 倒叙遍历,优化一维数组
for(int j =n;j >=w[i];j--){
dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
}
}
cout << dp[n];
}
实例:洛谷B3873 [GESP202309 六级] 小杨买饮料
/*以价格为背包的容量
饮料的最大容量为背包的最大价值
dp[j]表示每个价格的背包所能获得的最大容量 */
#include<bits/stdc++.h>
using namespace std;
// 单个饮料的价格为100
const int price_N = 100;
int dp[510*price_N+1];
int main() {
int c, l;
int N, L; // 物品个数和背包容量
cin >> N >> L;
for (int i = 1; i <= N; i++) {
cin >> c >> l;
for (int j =510*price_N ; j >= c; j--) { // 从背包容量开始递减
if (dp[j - c] != -1) { //判断数组是否被初始化
dp[j] = max(dp[j], dp[j - c] + l);
}
}
}
int ans = -1;
for (int i = 1; i <= 510*price_N; i++) {
if (dp[i] >= L) {
ans = i;
break;
}
}
ans == -1 ? cout << "no solution\n" : cout << ans << '\n';
return 0;
}
Ps:在做这道题的时候,遇到了一些bug,在动态规划中使用 -1 作为未初始化的标志是一个常见的约定,我将数组定义在主函数外面,他的值都是0,但是注意,这个时候的数组并没有被真正的初始化,加上这个未初始化的判断条件至关重要!
参考资料及相关链接