day35 动态规划03

87 阅读2分钟

文章讲解

思路1:

 dp[i][j]表示容量为j的背包装前i个物品的最大价值,从1开始。
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+1)]
for i in range(1, n+1):
    for j in range(1, bagweight+1):
        cur_w = weight[i-1]
        if cur_w > j:
            dp[i][j] = dp[i-1][j] # 容量不够;不加入当前物品,继承前i-1个物品的最大价值
        else:
            dp[i][j] = max(dp[i-1][j], # 不选择当前物品
                          dp[i-1][j-cur_w] + value[i-1]) # 选择当前物品
print(dp[n][bagweight])

思路2:

对于 0-1 背包问题,**滚动数组优化** 是最有效的优化方法,可以显著减少空间占用,并且在某些情况下可以提高运行速度。
n, bagweight = map(int, input().split())
weight = list(map(int, input().split()))
value = list(map(int, input().split()))

dp = [0] * (bagweight + 1)

for i in range(n):
    cur_w = weight[i]
    cur_v = value[i]
    for j in range(bagweight, cur_w - 1, -1):  # 从后往前遍历
        dp[j] = max(dp[j], dp[j - cur_w] + cur_v)

print(dp[bagweight])

416. 分割等和子集

文章讲解

思路:

1 先判断是否和为偶数,否则false
2 转换为0-1背包问题,只要找到元素的子集和为sum//2,那剩下的元素和与前面的相同。
class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        total = sum(nums)
        # 必须是偶数
        if total % 2 == 1:
            return False
        
        n = len(nums)
        target = total // 2
        # dp[i][j]表示容量为j的背包是否能装下 前i个数字(的子集,可以是空集,所以容量为0时候true)
        dp = [[False] * (target+1) for _ in range(n+1)]

        # 初始化 容量为0 true
        for i in range(n+1):
            dp[i][0] = True # 空集和为0
        
        for i in range(1, n+1):
            for j in range(1, target+1):
                if nums[i-1] > j:
                    dp[i][j] = dp[i-1][j]
                else:
                    dp[i][j] =  dp[i-1][j] or dp[i-1][j-nums[i-1]] # 注意是bool
        return dp[n][target]