Skip to content

Commit

Permalink
讲清楚如何转化01背包
Browse files Browse the repository at this point in the history
  • Loading branch information
youngyangyang04 committed Dec 11, 2024
1 parent 9768c91 commit 1a47aea
Showing 1 changed file with 20 additions and 22 deletions.
42 changes: 20 additions & 22 deletions problems/1049.最后一块石头的重量II.md
Original file line number Diff line number Diff line change
Expand Up @@ -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表示容量,那么最大容量(重量)是多少呢,就是所有石头的重量和。

Expand All @@ -95,7 +96,7 @@
vector<int> dp(15001, 0);
```

4. 确定遍历顺序
### 4. 确定遍历顺序


[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中就已经说明:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历!
Expand All @@ -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数组状态图如下:

Expand Down Expand Up @@ -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)相当于是求背包是否正好装满,而本题是求背包最多能装多少**。
## 其他语言版本
Expand Down

0 comments on commit 1a47aea

Please sign in to comment.