【Day30】卡码网:46. 携带研究材料,LeetCode:416. 分割等和子集

文章目录

卡码网:46. 携带研究材料

https://kamacoder.com/problempage.php?pid=1046

0-1背包问题,二维

思路

  1. 定义:dp[i][j] 表示只考虑前 i 件物品(索引从 0i ),在背包容量为 j 时能获得的最大价值。最终目标为 dp[n-1][bag]
  2. 状态转移方程:
    (1)当 j < weight[i](当前容量放不下第 i 件物品)时:
    dp[i][j] = dp[i-1][j] ,即不选第 i 件,结果与前 i - 1 件相同。
    (2)当 j >= weight[i](可以放下第 i 件物品)时:
    dp[i][j] = max(dp[i-1][j], dp[i-1][j - weight[i]] + value[i])
    不选:价值为 dp[i-1][j]
    选:先腾出 weight[i] 的空间( j - weight[i] ),加上第 i 件的价值。
  3. 初始化:所有 dp[i][j] 初始化为0。

解答

python 复制代码
first_line = input().split()
n = int(first_line[0])
bag = int(first_line[1])

second_line = input().split()
third_line = input().split()
weight = [int(x) for x in second_line]
value = [int(x) for x in third_line]

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

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

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

0-1背包问题,一维

思路

  1. 定义:dp[j] 表示当前考虑的物品范围内,背包容量为 j 时能获得的最大价值。
  2. 状态转移方程:dp[j] = max(dp[j], dp[j - w] + v) (j >= w)
  3. 初始化:dp = [0] * (bag + 1)

解答

python 复制代码
first_line = input().split()
n = int(first_line[0])
bag = int(first_line[1])

second_line = input().split()
third_line = input().split()
weight = [int(x) for x in second_line]
value = [int(x) for x in third_line]

dp = [0] * (bag + 1) # dp[j] 表示容量 j 能获得的最大价值

for i in range(n):
    w = weight[i]
    v = value[i]
    # 逆序遍历,保证每种物品只选一次
    for j in range(bag, w - 1, -1):
        dp[j] = max(dp[j], dp[j - w] + v)

print(dp[bag])

LeetCode:416. 分割等和子集

https://leetcode.cn/problems/partition-equal-subset-sum/description/
添加链接描述

思路

转化为01-背包问题:每个元素只能选或不选,背包容量为 target,求是否能恰好装满。

解答

python 复制代码
class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        total = sum(nums)
        # 总和为奇数则无法平分
        if total % 2 != 0:
            return False
        
        target = total // 2
        n = len(nums)
        
        # dp[j] 表示当前已考虑的元素能否凑出和为 j
        dp = [False] * (target + 1)
        dp[0] = True
        
        for num in nums:
            # 从后往前更新,避免重复使用当前元素
            for j in range(target, num - 1, -1):
                dp[j] = dp[j] or dp[j - num]
        
        return dp[target]
相关推荐
We་ct14 小时前
LeetCode 5. 最长回文子串:DP + 中心扩展
前端·javascript·算法·leetcode·typescript
做怪小疯子17 小时前
华为笔试0429
python·numpy
Warson_L18 小时前
Dictionary
python
王老师青少年编程18 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【哈夫曼贪心】:合并果子
c++·算法·贪心·csp·信奥赛·哈夫曼贪心·合并果子
叼烟扛炮19 小时前
C++第二讲:类和对象(上)
数据结构·c++·算法·类和对象·struct·实例化
天疆说19 小时前
【哈密顿力学】深入解读航天器交会最优控制中的Hamilton函数
人工智能·算法·机器学习
寒山李白20 小时前
解决 python-docx 生成的 Word 文档打开时弹出“无法读取内容“警告
python·word·wps·文档·docx·qoder
wuweijianlove20 小时前
关于算法设计中的代价函数优化与约束求解的技术7
算法
leoufung20 小时前
LeetCode 149: Max Points on a Line - 解题思路详解
算法·leetcode·职场和发展
样例过了就是过了20 小时前
LeetCode热题100 最长公共子序列
c++·算法·leetcode·动态规划