讲清楚如何转化01背包

This commit is contained in:
programmercarl
2024-12-11 11:46:56 +08:00
parent 9768c91ee2
commit 1a47aea273

View File

@ -42,40 +42,41 @@
## 思路
如果对背包问题不熟悉先看这两篇:
如果对背包问题不熟悉的话先看这两篇:
* [动态规划关于01背包问题你该了解这些](https://programmercarl.com/背包理论基础01背包-1.html)
* [动态规划关于01背包问题你该了解这些滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)
* [01背包理论基础二维数组](https://programmercarl.com/背包理论基础01背包-1.html)
* [01背包理论基础一维数组)](https://programmercarl.com/背包理论基础01背包-2.html)
本题其实是尽量让石头分成重量相同的两堆,相撞之后剩下的石头最小,**这样就化解成01背包问题了**。
本题其实是尽量让石头分成重量相同的两堆(尽可能相同),相撞之后剩下的石头就是最小的。
是不是感觉和昨天讲解的[416. 分割等和子集](https://programmercarl.com/0416.分割等和子集.html)非常像了。
一堆的石头重量是sum那么我们就尽可能拼成 重量为 sum / 2 的石头堆。 这样剩下的石头堆也是 尽可能接近 sum/2 的重量。
那么此时问题就是有一堆石头,每个石头都有自己的重量,是否可以 装满 最大重量为 sum / 2的背包。
本题物品的重量为stones[i]物品的价值也为stones[i]
看到这里,大家是否感觉和昨天讲解的 [416. 分割等和子集](https://programmercarl.com/0416.分割等和子集.html)非常像了,简直就是同一道题
对应着01背包里的物品重量weight[i]和 物品价值value[i]
本题**这样就化解成01背包问题了**
**[416. 分割等和子集](https://programmercarl.com/0416.分割等和子集.html) 是求背包是否正好装满,而本题是求背包最多能装多少**。
物品就是石头物品的重量为stones[i]物品的价值也为stones[i]。
接下来进行动规五步曲:
1. 确定dp数组以及下标的含义
### 1. 确定dp数组以及下标的含义
**dp[j]表示容量这里说容量更形象其实就是重量为j的背包最多可以背最大重量为dp[j]**
可以回忆一下01背包中dp[j]的含义容量为j的背包最多可以装的价值为 dp[j]
相对于 01背包本题中石头的重量是 stones[i],石头的价值也是 stones[i]
相对于 01背包本题中石头的重量是 stones[i],石头的价值也是 stones[i] ,可以 “最多可以装的价值为 dp[j]” == “最多可以背的重量为dp[j]”
“最多可以装的价值为 dp[j]” 等同于 “最多可以背的重量为dp[j]”
2. 确定递推公式
### 2. 确定递推公式
01背包的递推公式为dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
本题则是:**dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]);**
一些同学可能看到这dp[j - stones[i]] + stones[i]中 又有- stones[i] 又有+stones[i],看着有点晕乎。
大家可以再去看 dp[j]的含义。
3. dp数组如何初始化
### 3. dp数组如何初始化
既然 dp[j]中的j表示容量那么最大容量重量是多少呢就是所有石头的重量和。
@ -95,7 +96,7 @@
vector<int> dp(15001, 0);
```
4. 确定遍历顺序
### 4. 确定遍历顺序
在[动态规划关于01背包问题你该了解这些滚动数组](https://programmercarl.com/背包理论基础01背包-2.html)中就已经说明如果使用一维dp数组物品遍历的for循环放在外层遍历背包的for循环放在内层且内层for循环倒序遍历
@ -111,7 +112,7 @@ for (int i = 0; i < stones.size(); i++) { // 遍历物品
```
5. 举例推导dp数组
### 5. 举例推导dp数组
举例,输入:[2,4,1,1]此时target = (2 + 4 + 1 + 1)/2 = 4 dp数组状态图如下
@ -154,10 +155,7 @@ public:
本题其实和[416. 分割等和子集](https://programmercarl.com/0416.分割等和子集.html)几乎是一样的只是最后对dp[target]的处理方式不同。
[416. 分割等和子集](https://programmercarl.com/0416.分割等和子集.html)相当于是求背包是否正好装满,而本题是求背包最多能装多少。
**[416. 分割等和子集](https://programmercarl.com/0416.分割等和子集.html)相当于是求背包是否正好装满,而本题是求背包最多能装多少**
## 其他语言版本