刷题第三十五天 动态规划 0-1背包问题 416. 分割等和子集

本文介绍了背包问题的两种解法:0-1背包的二维和一维动态规划,以及完全背包和多重背包的基本概念。详细阐述了动态规划的过程和代码实现,包括递推公式和初始化步骤。
摘要由CSDN通过智能技术生成

背包问题:

1. 0-1背包:n种物品,每种物品只有一个

2. 完全背包:n种物品,每种物品有无穷多个

3. 多重背包:n种物品,每种物品的个数各不相同

背包问题:每个物品都有自己的重量和价值,最多只能放的重量为m,最多的价值为多少

① 二维dp数组解法:

1. dp数组的含义

dp[i][j]: 下标为0到i的物品任取放进容量为j的背包里的最大价值

如果不放第i个物品 价值为dp[i - 1][j]

放物品i的价值 dp[i - 1][j - weight[i]] + value[i] (当前物品的价值加上剩余空间的最大价值)

2. 递推公式

dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i])

3. 初始化

第一列初始化为0,因为背包容量为0的情况,最大价值就是0

第一行初始化根据物品0的重量和价值来,如果背包重量大于等于物品0 的重量的元素,初始化为物品0的重量,小于的话初始化成0.

其他位置不需要初始化,或者初始化成任意值

4. 遍历顺序

对于二维dp数组求解0-1背包问题的遍历顺序都可以。

def test_2_wei_bag_problem1(weight, value, bagweight):
    # 二维数组
    dp = [[0] * (bagweight + 1) for _ in range(len(weight))]

    # 初始化
    for j in range(weight[0], bagweight + 1):
        dp[0][j] = value[0]

    # weight数组的大小就是物品个数
    for i in range(1, len(weight)):  # 遍历物品
        for j in range(bagweight + 1):  # 遍历背包容量
            if j < weight[i]:
                dp[i][j] = dp[i - 1][j]
            else:
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i])

    return dp[len(weight) - 1][bagweight]

if __name__ == "__main__":

    weight = [1, 3, 4]
    value = [15, 20, 30]
    bagweight = 4

    result = test_2_wei_bag_problem1(weight, value, bagweight)
    print(result)

② 一维dp数组解法

上一层拷贝到当前层,然后直接从当前层计算。每次计算都更新本行数据(滚动数组)

1. dp数组的含义

dp[j] 容量j的背包能装的最大价值

2. 递推公式

dp[j] = max(dp[j],dp[j - weight[i]] + value[i])

3. 初始化

因为取最大值,所以都初始化成0就行了

4. 遍历顺序

因为每次重复利用,所以需要倒序遍历,否则会重复计算。

只能先遍历物品 再遍历背包

def test_1_wei_bag_problem(weight, value, bagWeight):
    # 初始化
    dp = [0] * (bagWeight + 1)
    for i in range(len(weight)):  # 遍历物品
        for j in range(bagWeight, weight[i] - 1, -1):  # 遍历背包容量
            dp[j] = max(dp[j], dp[j - weight[i]] + value[i])

    return dp[bagWeight]


if __name__ == "__main__":

    weight = [1, 3, 4]
    value = [15, 20, 30]
    bagweight = 4

    result = test_1_wei_bag_problem(weight, value, bagweight)
    print(result)

class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        val = sum(nums) / 2
        if val != int(val):
            return False
        else:
            val = int(val)
        # len(nums)个数中任取,能不能把容量为val的背包装满 dp[val] = val
        dp = [0] * (val + 1)
        for i in nums:                            #遍历物品,物品的重量为i,价值也为i
            for j in range(val, i - 1, -1):       #一维dp数组,反向遍历背包,遍历到物品的重量i为止
                dp[j] = max(dp[j], dp[j - i] + i)
        return dp[val] == val                     #判断容量为val的背包,装满的最大价值是不是等于val

转化为0-1背包问题:

背包容量为sum(nums)/2

物品的重量和质量都是nums[i]

容量为sum(nums)/2的背包能装的最大价值是否等于sum(nums)/2

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值