dp训练-背包问题-找零钱

总结,先东西/coins 遍历【外层】,再容量V/额度amount遍历【内层】
否则会有重复比较,多了很多重复方案的比较

0-1背包: 物品只能放进去一次

def bags_01(w:List,p:List, V:int)->int:
    #lenth = len(w)
    dp = [0 for _ in range(V+1)]
    for i,j in zip(w,p):
        for v in range(V, i-1,-1): #这个必须倒序,正序的话,从小容量到大容量遍历,一个物品可能被放进去多次
        # 倒序的话,计算大容量的时候,小容量还没有更新,不会在小容量的基础上再放入,也就是不会重复放入
            dp[v] = max(dp[v], dp[v-i]+j)
    return dp[V]

完全背包,物品有无穷件

def bags_2(w:List,p:List, V:int)->int:
    dp = [0 for _ in range(V + 1)]
    for i, j in zip(w, p):
        for v in range(i, V+1): #物品有无穷件,就可以重复放入,可以正着遍历
            dp[v] = max(dp[v], dp[v - i] + j)
    return dp[V]

第三道:找零的最小方案(给一些特定的零钱,输出张数最小的方案。)

题目:给定不同面额的硬币coins,和一个总金额change.用最小的硬币数量。如果没有组合达到,返回-1.
输入1:1,2,5;11
输出1:3(5+5+1)

输入2:2;3
输出2:-1
#力扣322

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        dp = [amount+1 for _ in range(amount+1)] #最小方案,初始化的时候就使用最大
        dp[0] = 0
        for c in coins: #外层循环是coins,weights
            for i in range(c,amount+1): #内层循环是amount,V; 否则会重复比较!!!!
                dp[i] = min(dp[i], dp[i-c]+1)#零钱有无数张,就可以正着遍历
        res = dp[amount]
        return res if res<amount+1 else -1

找零钱变种:装箱问题

'''
有重量分别为3,5,7公斤的三种货物,和一个载重量为X公斤的箱子(不考虑体积等其它因素,只计算重量)
需要向箱子内装满X公斤的货物,要求使用的货物个数尽可能少(三种货物数量无限)

输入箱子载重量X(1 <= X <= 10000),一个整数。

如果无法装满,输出 -1。
如果可以装满,输出使用货物的总个数。
1.必须装满
2.装货数量尽可能少
3. 这不就是找零钱吗
'''
X = int(input().strip())
W = [3,5,7]
dp = [X+1 for _ in range(X+1)] #dp[i] 装满i公斤最小装货数量
dp[0] = 0
for w in W:
    for i in range(w,X+1): #(三种货物数量无限)可以正着遍历
        dp[i] = min(dp[i], dp[i-w]+1)
ans = dp[X]
if ans<=X:
    print(ans)
else:
    print(-1)

零钱问题变换:

'''
力扣518
给定不同面额的硬币和一个总金额。
写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。 
'''
class Solution:
    def change(self, amount: int, coins: List[int]) -> int:
        dp = [0 for _ in range(amount+1)] #dp[i], 可以凑成i元的组合数
        dp[0] = 1
        for c in coins:#这时候,就显出来为什么coins/weights必须在外层,不会重复访问,每一轮c, dp[i]最多只能增加1
            for i in range(c,amount+1):#正序,因为有无数张
                dp[i] += dp[i-c]
        return dp[amount]
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值