forked from itcharge/AlgoNote
-
Notifications
You must be signed in to change notification settings - Fork 0
[pull] main from itcharge:main #67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
79 changes: 75 additions & 4 deletions
Contents/10.Dynamic-Programming/04.Knapsack-Problem/01.Knapsack-Problem.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,92 @@ | ||
## 1. 背包问题简介 | ||
|
||
> **背包问题**:背包问题是线性 DP 问题中一类经典而又特殊的模型。背包问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。 | ||
### 1.1 背包问题的定义 | ||
|
||
> **背包问题**:背包问题是线性 DP 问题中一类经典而又特殊的模型。背包问题可以描述为:给定一组物品,每种物品都有自己的重量、价格以及数量。再给定一个最多能装重量为 $W$ 的背包。现在选择一些物品放入背包中,请问在总重量不超过背包装载重量上限的情况下,能装入背包的最大价值总合是多少? | ||
|
||
根据物品限制条件的不同,背包问题可分为:0-1 背包问题、完全背包问题、多重背包问题、分组背包问题,以及混合背包问题等。 | ||
|
||
### 1.2 背包问题的暴力解题思路 | ||
|
||
背包问题的暴力解题思路比较简单。假设有 $n$ 件物品。我们先枚举出这 $n$ 件物品所有可能的组合。然后再对这些组合判断是否能放入背包,以及是否能得到最大价值。但是这种做法的时间复杂度是 $O(2^n),ドル其中 $n$ 表示物品数量。 | ||
|
||
暴力解法的时间复杂度是指数级别的,但是我们可以利用动态规划算法减少一下时间复杂度。 | ||
|
||
## 2. 0-1 背包问题 | ||
|
||
> **0-1 背包问题**:有 $n$ 件物品和有一个最多能装重量为 $W$ 的背包。第 $i$ 件物品的重量为 $weight[i],ドル价值为 $value[i],ドル每件物品有且只有 1ドル$ 件。请问在总重量不超过背包重量上限的情况下,能装入背包的最大价值是多少? | ||
> **0-1 背包问题**:有 $n$ 件物品和有一个最多能装重量为 $W$ 的背包。第 $i$ 件物品的重量为 $weight[i],ドル价值为 $value[i],ドル每件物品有且只有 1ドル$ 件。请问在总重量不超过背包装载重量上限的情况下,能装入背包的最大价值是多少? | ||
|
||
### 2.1 0-1 背包问题基本思路 | ||
|
||
> **0-1 背包问题的特点**:每种物品有且仅有 1ドル$ 件,可以选择放入背包,也可以选择不放入背包。 | ||
|
||
#### 思路 1:动态规划 | ||
|
||
###### 1. 划分阶段 | ||
|
||
按照物品的序号进行阶段划分。 | ||
|
||
###### 2. 定义状态 | ||
|
||
定义状态 $dp[i][w]$ 表示为:前 $i$ 件物品放入一个最多能装重量为 $w$ 的背包中,可以获得的最大价值。 | ||
|
||
状态 $dp[i][w]$ 是一个二维数组,其中第一维代表「当前正在考虑的物品」,第二维表示「当前背包的装载重量上限」,二维数组值表示「可以获得的最大价值」。 | ||
|
||
###### 3. 状态转移方程 | ||
|
||
对于「将前 $i$ 件物品放入一个最多能装重量为 $w$ 的背包中,可以获得的最大价值 」这个子问题,如果我们只考虑第 $i$ 件物品的放入策略(放入背包和不放入背包两种策略)。则问题可以转换为一个只跟前 $i - 1$ 件物品相关的问题。 | ||
|
||
1. **如果第 $i$ 件物品不放入背包**:问题转换为「前 $i - 1$ 件物品放入一个最多能装重量为 $w$ 的背包中 ,可以获得的最大价值为 $dp[i - 1][w]$」。 | ||
2. **如果第 $i$ 件物品放入背包**:问题转换为「前 $i - 1$ 件物品放入一个最多能装重量为 $w - weight[i]$ 的背包中,可以获得的最大价值为 $dp[i - 1][w - weight[i]]$」」,再加上「放入的第 $i$ 件物品的价值 $value[i]$」,则此时可以获得的最大价值为 $dp[i - 1][w - weight[i]] + value[i]$。 | ||
|
||
当然第 $i$ 件物品能够放入背包的前提是:当前背包的装载重量上限 ≥ 第 $i$ 件物品的重量,即 $w \ge weight[i]$。 | ||
|
||
则状态转移方程为: | ||
|
||
$dp[i][w] = max \begin{cases} dp[i - 1][w] & 第 i 件物品不放入背包 \cr dp[i - 1][w - weight[i]] + value[i] & 第 i 件物品放入背包 \end{cases}$ | ||
|
||
###### 4. 初始条件 | ||
|
||
- 如果背包容量为 0ドル,ドル则无论选取什么物品,可以获得的最大价值一定是 0ドル,ドル即 $dp[i][0] = 0$。 | ||
- 前 0ドル$ 件物品所能获得的最大价值一定为 0ドル,ドル即 $dp[0][w] = 0$。 | ||
|
||
###### 5. 最终结果 | ||
|
||
#### 思路 1:代码 | ||
|
||
```Python | ||
class Solution: | ||
def zeroOnePack(self, weight: [int], value: [int], W: int): | ||
size = len(weight) | ||
dp = [[0 for _ in range(W + 1)] for _ in range(size + 1)] | ||
|
||
for i in range(1, size + 1): | ||
for w in range(weight[i], W + 1): | ||
dp[i][w] = max(dp[i - 1][w], dp[i - 1][w - weight[i]] + value) | ||
|
||
return dp[size] | ||
``` | ||
|
||
#### 思路 1:复杂度分析 | ||
|
||
- **时间复杂度**:$O(n \times W),ドル其中 $n$ 为物品数量,$W$ 为背包的装载重量上限。 | ||
- **空间复杂度**:$O(n \times W)$。 | ||
|
||
### 2.2 0-1 背包问题滚动数组优化 | ||
|
||
|
||
|
||
## 3. 完全背包问题 | ||
|
||
> **完全背包问题**:有 $n$ 种物品和一个最多能装重量为 $W$ 的背包,第 $i$ 件物品的重量为 $weight[i],ドル价值为 $value[i],ドル每种物品数量没有限制。请问在总重量不超过背包重量上限的情况下,能装入背包的最大价值是多少? | ||
> **完全背包问题**:有 $n$ 种物品和一个最多能装重量为 $W$ 的背包,第 $i$ 件物品的重量为 $weight[i],ドル价值为 $value[i],ドル每种物品数量没有限制。请问在总重量不超过背包装载重量上限的情况下,能装入背包的最大价值是多少? | ||
|
||
## 4. 多重背包问题 | ||
|
||
> **多重背包问题**:有 $n$ 种物品和一个最多能装重量为 $W$ 的背包,第 $i$ 种物品的重量为 $weight[i],ドル价值为 $value[i],ドル件数为 $count[i]$。请问在总重量不超过背包重量上限的情况下,能装入背包的最大价值是多少? | ||
> **多重背包问题**:有 $n$ 种物品和一个最多能装重量为 $W$ 的背包,第 $i$ 种物品的重量为 $weight[i],ドル价值为 $value[i],ドル件数为 $count[i]$。请问在总重量不超过背包装载重量上限的情况下,能装入背包的最大价值是多少? | ||
|
||
## 5. 分组背包问题 | ||
|
||
## 参考资料 | ||
|
||
- 【资料】[背包九讲 - 崔添翼](https://github.com/tianyicui/pack) | ||
- 【文章】[背包 DP - OI Wiki](https://oi-wiki.org/dp/knapsack/) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
Templates/10.Dynamic-Programming/Pack-ZeroOnePack.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
class Solution: | ||
def zeroOnePack(self, weight: [int], value: [int], W: int): | ||
size = len(weight) | ||
dp = [[0 for _ in range(W + 1)] for _ in range(size + 1)] | ||
|
||
for i in range(1, size + 1): | ||
for w in range(weight[i], W + 1): | ||
dp[i][w] = max(dp[i - 1][w], dp[i - 1][w - weight[i]] + value) | ||
|
||
return dp[size] | ||
|
||
def zeroOnePackOptimization(self, weight: [int], value: [int], W: int): | ||
size = len(weight) | ||
dp = [0 for _ in range(W + 1)] | ||
|
||
for i in range(1, size + 1): | ||
for w in range(W, weight[i] - 1, -1): | ||
dp[w] = max(dp[w], dp[w - weight[i]] + value[i]) | ||
|
||
return dp[size] |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.