最近在复习算法知识写下这篇文章帮助自己理解记忆
01 背包问题
01背包问题的目标是在固定的容量限制内,达到最大的物品价值
01对含义:无法分割物品
01背包问题通常有暴力回溯法和动态规划两种方式来解决
Brute Force
回溯法检查所有组合 时间复杂度为指数级
很容易时间就爆表,这里就不看了
动态规划
动态规划的核心在于寻找子问题,在这个题中我们首先去寻找子问题
寻找子问题
假设背包最大重量为5
物品信息如下
重量 | 价值 | |
---|---|---|
物品1 | 4 | 7 |
物品2 | 3 | 5 |
物品3 | 5 | 6 |
物品4 | 3 | 3 |
物品5 | 2 | 8 |
dp表的每一个位置存储的是这么大的背包,最大收益是多少
我们首先考虑,如果只有物品1, 如果装不下,收益就是0
如果我们的背包可以装下,那么最大收益就是7,我们更新第一行
0 | 1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|---|
物品1 | 0 | 0 | 0 | 0 | 7 | 7 |
物品2 | ||||||
物品3 | ||||||
物品4 | ||||||
物品5 |
通过解决子问题获得到全局问题的解
现在考虑物品2,如果装不下,收益就是上一行相同位置的结果
如果能装下:判断上一行相同位置的结果 此物品价值加上上一行去掉此物品重量后的重量最多能装的价值
由此我们获得状态转移方程
dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight[i]]+values[i])
0 | 1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|---|
物品1 | 0 | 0 (4 - weight of item 2) | 0 | 0 | 7 | 7 |
物品2 | 0 | 0 | 0 | 5 | max(7, (5 + 0)) | |
物品3 | ||||||
物品4 | ||||||
物品5 |
不断迭代
0 | 1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|---|
物品1 | 0 | 0 | 0 | 0 | 7 | 7 |
物品2 | 0 | 0 | 0 | 5 | 7 | 7 |
物品3 | 0 | 0 | 0 | 5 | 7 | 7 |
物品4 | 0 | 0 | 0 | 5 | 7 | 7 |
物品5 | 0 | 0 | 8 | 8 | 8 | 13 |
最后结果为13
完整Python代码如下
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 计算01背包问题的结果
# @param V int整型 背包的体积
# @param n int整型 物品的个数
# @param vw int整型二维数组 第一维度为n,第二维度为2的二维数组,vw[i][0],vw[i][1]分别描述i+1个物品的vi,wi
# @return int整型
#
class Solution:
def knapsack(self, V: int, n: int, vw: List[List[int]]) -> int:
# write code here
dp = [[0] * (V + 1) for _ in range(n)]
for i in range(V + 1):
if i >= vw[0][0]:
dp[0][i] = vw[0][1]
for i in range(1, n):
for j in range(V + 1):
if j < vw[i][0]:
dp[i][j] = dp[i-1][j]
else:
dp[i][j] = max(dp[i-1][j], dp[i-1][j-vw[i][0]]+vw[i][1])
return dp[n-1][V]
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。