2024.08.06 代码随想录 | 动态规划 背包问题

70. 爬楼梯(进阶版)

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 

每次你可以爬至多m (1 <= m < n)个台阶。你有多少种不同的方法可以爬到楼顶呢? 

注意:给定 n 是一个正整数。

n, m = map(int, input().split())

dp = [0] * (n+1)
dp[0] = 1
for j in range(1, n+1):
    for i in range(1, m+1):
        if j >= i:
            dp[j] += dp[j-i]

print(dp[n])
    

322. 零钱兑换*

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1

你可以认为每种硬币的数量是无限的。

随想录解法:推导出来了状态转移方程,但是卡在了dp数组的初始化,不能全部初始化为0或者-1,因为这两个数都是有含义的。因为要取最小值,自然初始化成最大值

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        # dp = [-1] * (amount+1)
        # dp[0] = 0
        # # if num == j: dp[j] = 1
        # # dp[j] = min(dp[j], dp[j-num]+1) if dp[j] > 0 else dp[j-num] + 1
        # # * 0 1 2 3 4 5 6
        # # 1 0 1 2 3 4 5 6
        # # 2 0 1 1 2 2 3 3
        # for coin in coins:
        #     for j in range(coin, amount+1):
        #         if coin == j:
        #             dp[j] = 1
        #         elif dp[j] >= 0:
        #             dp[j] = min(dp[j], dp[j-coin] + 1)
        #         elif dp[j-coin] >= 0:
        #             dp[j] = dp[j-coin] + 1
        #         else:
        #             dp[j] = -1
        # return dp[amount]
        dp = [float('inf')] * (amount + 1)  # 创建动态规划数组,初始值为正无穷大
        dp[0] = 0  # 初始化背包容量为0时的最小硬币数量为0

        for coin in coins:  # 遍历硬币列表,相当于遍历物品
            for i in range(coin, amount + 1):  # 遍历背包容量
                if dp[i - coin] != float('inf'):  # 如果dp[i - coin]不是初始值,则进行状态转移
                    dp[i] = min(dp[i - coin] + 1, dp[i])  # 更新最小硬币数量

        if dp[amount] == float('inf'):  # 如果最终背包容量的最小硬币数量仍为正无穷大,表示无解
            return -1
        return dp[amount]  # 返回背包容量为amount时的最小硬币数量

279.完全平方数

给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,149 和 16 都是完全平方数,而 3 和 11 不是。

class Solution:
    def numSquares(self, n: int) -> int:
        # items = []
        # for i in range(1, n):
        #     if i * i < n:
        #         items.append(i)
        dp = [n] * (n+1)
        dp[0] = 0
        for i in range(1, n + 1):
            for j in range(i*i, n+1):
                dp[j] = min(dp[j], dp[j-i*i] + 1)
        return dp[n]

 139.单词拆分

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true

注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。

难点在于给出动态数组的递推公式:

如果确定dp[j] 是true,且 [j, i] 这个区间的子串出现在字典里,那么dp[i]一定是true。(j < i )。

class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        dp = [False]*(len(s) + 1)
        dp[0] = True
        # 遍历背包
        for j in range(1, len(s) + 1):
            # 遍历单词
            for word in wordDict:
                if j >= len(word):
                    dp[j] = dp[j] or (dp[j - len(word)] and word == s[j - len(word):j])
        return dp[len(s)]

多重背包问题*

有N种物品和一个容量为V 的背包。第i种物品最多有Mi件可用,每件耗费的空间是Ci ,价值是Wi 。求解将哪些物品装入背包可使这些物品的耗费的空间 总和不超过背包容量,且价值总和最大。

每件物品最多有Mi件可用,把Mi件摊开,其实就是一个01背包问题了。

C, N = input().split(" ")
C, N = int(C), int(N)

# value数组需要判断一下非空不然过不了
weights = [int(x) for x in input().split(" ")]
values = [int(x) for x in input().split(" ") if x]
nums = [int(x) for x in input().split(" ")]

dp = [0] * (C + 1)
# 遍历物品
for i in range(N):
    # 遍历背包容量
    for j in range(C, weights[i] - 1, -1):
        for k in range(1, nums[i] + 1):
            # 遍历 k,如果已经大于背包容量直接跳出循环
            if k * weights[i] > j:
                break
            dp[j] = max(dp[j], dp[j - weights[i] * k] + values[i] * k) 
print(dp[-1])

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值