01 背包问题

最近在复习算法知识写下这篇文章帮助自己理解记忆

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]

你可能感兴趣的:(算法动态规划)