leetcode-背包问题

问题描述

给你一个装载重量为 W 的背包和 N 个物品,每个物品有重量和价值两个属性。其中第 i 个物品的重量为 \(wt[i]\),价值为 \(val[i]\),现在让你用这个背包装物品,最多能装的价值是多少?

示例

 N = 3, W = 4
 wt = [2, 1, 3]
 val = [4, 2, 3]

返回6,选择前两件物品,总重量小于W,可获得最大价值6.

动态规划

状态和选择

状态有两个,就是「背包的容量」和「可选择的物品」。
对于每件物品,你能选择什么?选择就是「装进背包」或者「不装进背包

动态规划框架

for 状态1 in 状态1的所有取值:
    for 状态2 in 状态2的所有取值:
        for ...

            dp[状态1][状态2][... = 择优(选择1,选择2...)

明确dp含义

首先看看刚才找到的「状态」,有两个,也就是说我们需要一个二维 dp 数组
dp[i][w]定义:对于前 i 个物品,当前背包的容量为 w,这种情况下可以装的最大价值是 dp[i][w]

比如说,如果 dp[3][5] = 6,其含义为:对于给定的一系列物品中,若只对前 3 个物品进行选择,当背包容量为 5 时,最多可以装下的价值为 6。

根据选择,状态转移

如果没有把这第 i 个物品装入背包,那么很显然,最大价值 \(dp[i][w] = dp[i-1][w]\),继承之前的结果。

如果把这第 i 个物品装入了背包,那么 \(dp[i][w] = dp[i-1][w - wt[i-1]] + val[i-1]\).
若装了第 i 个物品,就要寻求剩余重量 \(w-wt[i-1]\) 限制下的最大价值,加上第 i 个物品的价值 \(val[i-1]\)

代码实现

def backpack(W:int, N:int,wt: List[int], val: List[int]):
    # dp[i][j]对于前i个物品,背包容量为j,所装的价值是dp[i][j]

    dp = [[0]*(W+1) for _ in range(N+1)]
    
    for i in range(1,N+1):
        for j in range(1,W+1):

            # 若不选择第i个物品
            if j<wt[i-1]:
                dp[i][j] = dp[i-1][j]
            
			# 若选择第i个物品
            else:
                dp[i][j] = max(dp[i-1][j-wt[i-1]]+val[i-1],dp[i-1][j])

    return dp[N][W] 

参考

posted @ 2022-03-15 20:37  topbookcc  阅读(200)  评论(0编辑  收藏  举报
/* 鼠标点击求赞文字特效 */