代码随想录算法训练营第三十九天|背包问题,416. 分割等和子集

背包问题,416. 分割等和子集

    • 背包问题
    • [416. 分割等和子集](#416. 分割等和子集)

背包问题

有N件物品和一个最多能背重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。

卡玛网的代码参考

python 复制代码
n, bagweight = map(int, input().split())

weight = list(map(int, input().split()))
value = list(map(int, input().split()))

dp = [[0] * (bagweight + 1) for _ in range(n)]

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

for i in range(1, n):
    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])

print(dp[n - 1][bagweight])

一维dp 的01背包初始化和遍历顺序更简单,一维dp数组的背包在遍历顺序上和二维不同,使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历。

python 复制代码
n, bagweight = map(int, input().split())
weight = list(map(int, input().split()))
value = list(map(int, input().split()))

dp = [0] * (bagweight + 1)  # 创建一个动态规划数组dp,初始值为0

dp[0] = 0  # 初始化dp[0] = 0,背包容量为0,价值最大为0

for i in range(n):  # 应该先遍历物品,如果遍历背包容量放在上一层,那么每个dp[j]就只会放入一个物品
    for j in range(bagweight, weight[i]-1, -1):  # 倒序遍历背包容量是为了保证物品i只被放入一次
        dp[j] = max(dp[j], dp[j - weight[i]] + value[i])

print(dp[bagweight])

416. 分割等和子集

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

注意: 每个数组中的元素不会超过 100 数组的大小不会超过 200

示例 1 :
输入 : [1, 5, 11, 5]
输出 : true
解释: 数组可以分割成 [1, 5, 5] 和 [11].

示例 2 :
输入 : [1, 2, 3, 5]
输出 : false
解释: 数组不能分割成两个元素和相等的子集.

参考代码,重点掌握一维的方法。

python 复制代码
class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        _sum = 0

        # dp[i]中的i表示背包内总和
        # 题目中说:每个数组中的元素不会超过 100,数组的大小不会超过 200
        # 总和不会大于20000,背包最大只需要其中一半,所以10001大小就可以了
        dp = [0] * 10001
        for num in nums:
            _sum += num
        # 也可以使用内置函数一步求和
        # _sum = sum(nums)
        if _sum % 2 == 1:
            return False
        target = _sum // 2

        # 开始 0-1背包
        for num in nums:
            for j in range(target, num - 1, -1):  # 每一个元素一定是不可重复放入,所以从大到小遍历
                dp[j] = max(dp[j], dp[j - num] + num)

        # 集合中的元素正好可以凑成总和target
        if dp[target] == target:
            return True
        return False

简化

python 复制代码
class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        if sum(nums) % 2 != 0:
            return False
        target = sum(nums) // 2
        dp = [0] * (target + 1)
        for num in nums:
            for j in range(target, num-1, -1):
                dp[j] = max(dp[j], dp[j-num] + num)
        return dp[-1] == target

二维DP

python 复制代码
class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        
        total_sum = sum(nums)

        if total_sum % 2 != 0:
            return False

        target_sum = total_sum // 2
        dp = [[False] * (target_sum + 1) for _ in range(len(nums) + 1)]

        # 初始化第一行(空子集可以得到和为0)
        for i in range(len(nums) + 1):
            dp[i][0] = True

        for i in range(1, len(nums) + 1):
            for j in range(1, target_sum + 1):
                if j < nums[i - 1]:
                    # 当前数字大于目标和时,无法使用该数字
                    dp[i][j] = dp[i - 1][j]
                else:
                    # 当前数字小于等于目标和时,可以选择使用或不使用该数字
                    dp[i][j] = dp[i - 1][j] or dp[i - 1][j - nums[i - 1]]

        return dp[len(nums)][target_sum]

一维DP

python 复制代码
class Solution:
    def canPartition(self, nums: List[int]) -> bool:

        total_sum = sum(nums)

        if total_sum % 2 != 0:
            return False

        target_sum = total_sum // 2
        dp = [False] * (target_sum + 1)
        dp[0] = True

        for num in nums:
            # 从target_sum逆序迭代到num,步长为-1
            for i in range(target_sum, num - 1, -1):
                dp[i] = dp[i] or dp[i - num]
        return dp[target_sum]
相关推荐
小白学大数据5 分钟前
基于Python的新闻爬虫:实时追踪行业动态
开发语言·爬虫·python
freed_Day7 分钟前
python面向对象编程详解
开发语言·python
满分观察网友z8 分钟前
别总想着排序!我在数据看板中悟出的O(N)求第三大数神技(414. 第三大的数)
算法
满分观察网友z9 分钟前
别只知道暴力循环!我从用户名校验功能中领悟到的高效字符集判断法(1684. 统计一致字符串的数目)
算法
刚入坑的新人编程14 分钟前
暑期算法训练.9
数据结构·c++·算法·leetcode·面试·排序算法
码事漫谈18 分钟前
AGI就像暴雨,可能说来就来
算法
普郎特34 分钟前
张三:从泥水匠到包工头的故事 *—— 深入浅出讲解 `run_in_executor()` 的工作原理*
python
workflower35 分钟前
数据分析前景
算法·数据挖掘·数据分析·需求分析·软件需求
我要学习别拦我~1 小时前
kaggle分析项目:steam付费游戏数据分析
python·游戏·数据分析
阿鼎08151 小时前
揭秘大语言模型:从文字到数字,token 是如何变成向量的?
人工智能·算法