Suzy心情很差因为被charge了late fee Day42 | 动态规划之背包问题,416. 分割等和子集

背包问题

01背包

Given

  1. n种物品,每种物品只有1个
  2. 每个物品有自己的重量、价值。
  3. 背包最大能装载的重量

动规五部曲——用二维数组

  1. 定义dp数组的含义:dp[ i ][ j ]表示[0,i]物品,任取放在容量为j的背包。
  2. 递推数组dp[i][j]:
    (1)不放物品i,则所选的物品少1:dp[i-1][j]
    (2)放物品i,则背包容量需要减去i的重量:dp[i-1][j-weight[i]]+value[i]
    (3)dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i])
  3. 如何初始化dp数组:dp[i][j]是由上面的dp[i-1][j]和左上方的某一个元素推至。所以需要初始化第一行和第一列,然后按照递推公式确定后续的所有。
    (1)第一列初始化:dp[k][0]=0, k=0,…,n-1
    (2)第一行初始化:dp[0][k]按照物品0的重量决定
    (3)其余任意

动规五部曲——用一维数组

链接: 01背包问题用一维数组
把二维dp数组降为一维——滚动数组

  1. 定义dp[j]表示容量为j的背包能放最大价值为dp[j]的物品
  2. 递推数组:
    滚动数组的每一次更新,比如第i次更新,就是表示对于物品i的决策。相当于在二维数组中,把下一行的值直接在本行进行更新,所以先前的dp[j]是存储了不放物品i的
    dp[j]=max(dp[j],dp[j-weight[i]]+value[i])
  3. 初始化:
    dp[0]=0
    因为dp[j]是在自己原来的值和另外一个值取max,所以自己的初始化不能太大,不然会覆盖真实的情况。
    所以其余全部可以初始化为0
  4. 遍历顺序
    先遍历物品->再倒叙遍历背包(倒叙保证物品只被添加一次)

416. 分割等和子集

题目

给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

怎么靠到动态规划01背包问题

  1. 一开始我的笨蛋想法是从大到小遍历整个数组中的元素,用两个数组来装。对于元素i,如果当前数组sum1>sum2,就放到2,否则放到1中,但是这是错误的。对于【5,4,3,3,3】。
  2. 靠向背包问题:切割为和相等的两个数组。nums总和为sum时,即有一个背包容量为sum/2的背包,nums数组是物品的重量,找到把背包装满的物品。

solution(二维)

class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        if sum(nums)%2==1:return False
        package=int(sum(nums)/2) # 背包容量11
        temp=[0]*(package+1) 
        dp=[]
        for i in range(len(nums)):
            dp.append(temp.copy())
        
        # dp[i][j]=max(dp[i-1][j]],dp[i-1][j-nums[i]]+nums[i])
        # if dp[i][package]==package:return True
        # if traversal items finished, return False
        for i in range(len(nums)):dp[i][0]=0
        for j in range(len(dp[0])):
            if j>=nums[0]:dp[0][j]+=nums[0]

        for i in range(len(nums)):
            for j in range(len(dp[0])):
                # 我们的目的是尽可能地装满我们的背包容量,即最多的价值的物品
                # 如果dp[-1][package]==package,说明我们决策完所有的物品后,能装到的最大价值(重量)如果与背包容量相等,则说明可以分割数组。否则不满足。
                if j>=nums[i]:
                    dp[i][j]=max(dp[i-1][j],dp[i-1][j-nums[i]]+nums[i])
                else:
                    dp[i][j]=dp[i-1][j]
                
        if dp[-1][-1]==package:return True
        return False

递推公式处需要进行判断,当前的容量是否可以装,可以装才有递推公式(选到底装还是不装),不可以装就只有一种情况。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值