代码随想录训练营打卡Day34| 动态规划part03
0/1背包理论基础
题目链接:01背包理论基础
小明是一位科学家,他需要参加一场重要的国际科学大会,以展示自己的最新研究成果。他需要带一些研究材料,但是他的行李箱空间有限。这些研究材料包括实验设备、文献资料和实验样本等等,它们各自占据不同的空间,并且具有不同的价值。
小明的行李空间为 N,问小明应该如何抉择,才能携带最大价值的研究材料,每种研究材料只能选择一次,并且只有选与不选两种选择,不能进行切割。
思路:每一件物品其实只有两个状态,取或者不取【可以用回溯的思想来找到最优解,O(2^n)】;
动规五部曲分析:
1. 确定dp数组以及下标的含义:dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少
2. 确定递推公式:新纳入物品重量超过背包重量,继承上方单元格;
比较 dp[背包容量 - 新加入物品] + 新加入物品价值 和 上方单元格 取最大值;3. dp数组如何初始化
4. 确定遍历顺序:外层遍历是物品顺序,内层遍历是背包容量;
5. 举例推导dp数组
【要注意
dp[i-1]越界的问题】
// 一维01背包模板,必须外层是物品、内层是容量倒序;
vector<int> dp(W + 1, 0);
for (int i = 1; i <= n; ++i) {            // 外层物品for (int j = W; j >= w[i]; --j) {     // 内层容量,必须倒序dp[j] = max(dp[j], dp[j - w[i]] + v[i]);}
}// 二维01背包,内外层顺序无所谓;
vector<vector<int>> dp(n + 1, vector<int>(W + 1,0));  // m 是容量上限
for(int i = 1; i < n; i++) {for(int j = 0; j < W; j++) {if(w[i] > j) dp[i][j] = dp[i-1][j];dp[i][j] = max(dp[i-1][j - w[i]] + v[i], dp[i-1][j]);}
} 
 
416. 分割等和子集
题目链接:416. 分割等和子集
给你一个 只包含正整数 的 非空 数组
nums。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
思路:抽象为01背包;
Q:如何抽象为01背包?
A:这题就是经典的「等和分割 → 子集和 = 总和一半」,可直接抽象成0/1 背包
能否从
nums里选一些数,使它们的和恰好等于target = S/2Q:这种抽象为01背包的思路是什么?有什么固定的套路或者特征?
A:只要你的题能转成 “在若干个元素中选择一部分,使它们满足某个约束(≤ / = / 恰好),并使某个目标最大/是否可达”,就可以抽象成 0/1 背包
✅ Step 1:识别出“选择问题”:每个元素是否选 → 二元状态
✅ Step 2:找到“约束变量”(容量):问题中是否存在一个“上限”?
✅ Step 3:定义 dp 数组(状态转移)
PS:和两数之和这种问题的区别在于目标是找到恰好两个/三个数使和满足条件,而DP在于选部分数,使得和满足某种关系,而且每个数只有选/不选两种状态;
