【代码随想录day 35】 力扣 01背包问题 二维
视频讲解:https://www.bilibili.com/video/BV1cg411g7Y6/?vd_source=a935eaede74a204ec74fd041b917810c
文档讲解:https://programmercarl.com/%E8%83%8C%E5%8C%85%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%8001%E8%83%8C%E5%8C%85-1.html#%E6%80%9D%E8%B7%AF
力扣题目:https://kamacoder.com/problempage.php?pid=1046
这道题理解起来有点抽象。但是同其他动态规划的题一样,按步骤逐步分析
- 二维dp数组含义dp[i][j]:下标为0-i的物品任取,放进容量j的包里所能放的最大价值
- 递推公式:不放物品i时:dp[i - 1][j],放物品i时:dp[i - 1][j - weight[i]] + value(i),所以dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value(i))
- 初始化,dp[i][j]跟dp[i - 1][j] 和dp[i - 1][j - weight[i]]有关系,所以要初始化ij位置的左上角方向,即二维数组的最上一行和最左一列
- 遍历顺序,从上到下从左到右
这里需要注意的是,容量j是可以装满的,因此对容量的遍历是从0-N左闭右闭区间,在动归的遍历过程中,如果j的容量不足以放入第i个物品,则继承dp[i - 1][j]的值。
#include <bits/stdc++.h>
using namespace std;int main()
{//初始化物品M种,总容量Nint M, N;cin >> M >> N;vector<int> value(M);vector<int> weight(M);for(int i = 0; i < M; ++i){cin >> weight[i];}for(int i = 0; i < M; ++i){cin >> value[i];}//1.二维dp数组含义dp[i][j]:下标为0-i的物品任取,放进容量j的包里所能放的最大价值vector<vector<int>> dp(M, vector<int>(N + 1, -1));//2.递推公式//不放物品i时:dp[i - 1][j]//放物品i时:dp[i - 1][j - weight[i]] + value(i)//所以dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value(i))//3.初始化,dp[i][j]跟dp[i - 1][j] 和dp[i - 1][j - weight[i]]有关系,所以要初始化ij位置的左上角方向,即二维数组的最上一行和最左一列//初始化最左一列,因为最左一列时背包空间为0的情况,所以初始化均为0for(int i = 0; i < M; ++i){dp[i][0] = 0;}//初始化最上一行,因为最上一行是只放物品0的情况,所以只要判断背包空间j是否能放下weight[0]即可,如果能放下则初始化为物品0的价值,如果放不下则初始化为0for(int j = 0; j <= N; ++j){//当背包容量大于等于第一个物品的weight时,初始化为第1个物品的valueif(j >= weight[0]){dp[0][j] = value[0];continue;}dp[0][j] = 0;}//4. 遍历顺序,从上到下从左到右for(int i = 1; i < M; ++i){//物品的容量是可以装满的,所以是由 0 - N 左闭右闭区间for(int j = 1; j <= N; ++j){//如果空间不够放第i个物品,即j < weight[i]则继承前一个dp的值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[M - 1][N] << endl;return 0;}