理论内容都在代码随想录了,这里我主要是自己写题解回顾,强烈推荐
目录
模板一:二维数组版本
void test_2_wei_bag_problem1() {
vector<int> weight = {1, 3, 4};
vector<int> value = {15, 20, 30};
int bagweight = 4;
// 二维数组
vector<vector<int>> dp(weight.size(), vector<int>(bagweight + 1, 0));
// 初始化
for (int j = weight[0]; j <= bagweight; j++) {
dp[0][j] = value[0];
}
// weight数组的大小 就是物品个数
for(int i = 1; i < weight.size(); i++) { // 遍历物品
for(int j = 0; j <= bagweight; j++) { // 遍历背包容量
if (j < weight[i]) dp[i][j] = dp[i - 1][j];
else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
}
}
cout << dp[weight.size() - 1][bagweight] << endl;
}
int main() {
test_2_wei_bag_problem1();
}
问题:
(1)初始化问题:不能随意的凭感觉的初始化为0,或初始化为1,要根据实际情况
当这个点是初始点时,将数据带入,并检查,因为这个点时所有点的基石
当这个点不为初始点时,一般初始化为0(防止覆盖后面递推得出的数据)
比如在这个模板中:将第一行全部初始化为value[0]
意义为:当背包容量>=1时,如果只放第一件物品,那么背包所得到的最大价值就是value[0]
(2)for循环遍历顺序问题:
一般我们都是先正序遍历物品的重量,再正序遍历背包容量,但实际上,在二维数组中,这个顺序完全可以颠倒,即先正序遍历背包容量,再正序遍历物品的重量;
因为它们之间互相不会覆盖,所以不受影响,但是下面的一维数组就要考虑了
(3)递推公式问题:01背包模板递推公式:
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i])
含义:dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少
返回即返回dp[weight.size()-1][bagweight],也就是递推的最后一步
当不放入物品时:背包容量没有损失,最大价值等于上一个的价值(没有拿,价值不变)
当放入物品时:背包容量=背包容量-物品的重量,最大价值等于上一个的价值+新增物品的价值
模板二:一维数组版本(滚动数组)
#include<vector>
#include <stack>
#include<queue>
#include<iostream>
using namespace std;
void test()
{
vector<int> weight = { 1, 3, 4 };
vector<int> value = { 15, 20, 30 };
int bagweight = 4;
//核心是:物品重量作为底,将背包的最大容量作为天花板,将天花板依次--,直到正好等于底
//依次统计天花板降低时,dp[j]的最大价值
//之后再重新换一个底,重复上述步骤
vector<int> dp(bagweight + 1, 0);
for (int i = 0; i < weight.size(); i++)//物品重量
{
for (int j = bagweight; j >=