【数据结构】【递归】四.分治策略,优化贪心,找零兑换问题,动态优化

def recMC(coinValueList,change):
    minCoins = change
    if change in coinValueList:  # 最小规模,直接返回
        return 1
    else:
        for i in [c for c in coinValueList if c <= change]:
            # 减小规模:每次减去一种硬币面值挑选最小数量
            numCoins = 1 + recMC(coinValueList, change-i)  # 调用自身
            if numCoins < minCoins:
                minCoins = numCoins
    return minCoins

print(recMC([1,5,10,25], 63))

def recMC(coinValueList,change,knownResults):
    minCoins = change
    if change in coinValueList:  # 递归基本结束条件
        knownResults[change] = 1  # 记录最优解
        return 1
    elif knownResults[change] > 0:  # 算过的就会大于0
        return knownResults[change]  # 查表成功,直接用最优解
    else:
        for i in [c for c in coinValueList if c <= change]:
            # 减小规模:每次减去一种硬币面值挑选最小数量
            numCoins = 1 + recMC(coinValueList, change-i, knownResults)  # 调用自身
            if numCoins < minCoins:
                minCoins = numCoins
                # 找到最优解,记录到表中
                knownResults[change] = minCoins
    return minCoins


print(recMC([1,5,10,25], 63, [0]*64))

详细解释:https://zhuanlan.zhihu.com/p/139157497

def dpMakeChange(coinValueList, change, minCoins):
    """
    coinValueList:一个有效的硬币值列表
    change:找零金额
    minCoins:每个找零金额所需的最小硬币数量列表,函数完成后,将包含从0到change值的所有值的解决方案

    动态规划:其所求的最优解是由子问题的最优解构成的.
    动态规划是自底向上的计算.
    在找零递加的过程中,设法保持每一分钱的递加都是最优解,一直加到求解找零钱
    数,自然得到最优解
    """
    # 从1分开始到change逐个计算最少硬币数
    for cents in range(1, change + 1):  # 从1到63美分逐个计算
        coinCount = cents  # 初始化最小找零的硬币数,假设都用1美分找零,即123456789美分时找零硬币书就是123456789
        # 2.减去每个硬币,向后查最少硬币数,同时记录总的最少数
        for j in [c for c in coinValueList if c <= cents]:  # j在硬币面值小于找零美分中挑选
            if minCoins[cents - j] + 1 < coinCount:  # 若(当前找零美分-硬币面值)对应的找零数 < 该找零钱数的初始化硬币数,则不需要初始化那么多的硬币数
                coinCount = minCoins[cents - j] + 1  # 将最小找零硬币数改为最优列表的数值,即(当前找零美分-硬币面值)对应的找零数
        # 3.得到当前最少硬币数,记录到表中
        minCoins[cents] = coinCount  
        # minCoins[10] = 1,因为找零硬币有10美分的面值,所以找零数为10的时候只需要1个硬币
        # for循环的过程为,先j=1,判断10-1后的9美分所需的最小硬币是不是比初始化的10个少,是,则所需最小硬币数变为9美分需要的硬币数+1(这个1是j对应的硬币数需要1个),即6个
        # 接着判断j=5,判断10-5后的5美分需要的最小硬币数是不是比已有的6个少,是,则所需最小硬币数变为5美分需要的硬币数+1,即2个
        # 接着判断j=10,判断10-10后的0美分需要的最小硬币数是不是比已有的2个少,是,则所需最小硬币数变为0美分需要的硬币数+1,即1个
    # 返回最后一个结果
    return minCoins[change]


print(dpMakeChange([1,5,10,25], 11, [0]*12))
# print(dpMakeChange([1,5,10,21,25], 63, [0]*64))

def dpMakeChange(coinValueList, change, minCoins,coinsUsed):
    """
    coinValueList:一个有效的硬币值列表
    change:找零金额
    minCoins:每个找零金额所需的最小硬币数量列表,函数完成后,将包含从0到change值的所有值的解决方案
    """
    # 从1分开始到change逐个计算最少硬币数
    for cents in range(1, change + 1):  # 从1到63美分逐个计算
        coinCount = cents  # 初始化最小找零的硬币数,假设都用1美分找零,即123456789美分时找零硬币书就是123456789
        newCoin = 1  # 初始化一下新加硬币
        for j in [c for c in coinValueList if c <= cents]:  # j在硬币面值小于找零美分中挑选
            if minCoins[cents - j] + 1 < coinCount:  # 若(当前找零美分-硬币面值)对应的找零数 < 该找零钱数的初始化硬币数,则不需要初始化那么多的硬币数
                coinCount = minCoins[cents - j] + 1  # 将最小找零硬币数改为最优列表的数值,即(当前找零美分-硬币面值)对应的找零数
                newCoin = j  # 对应最小数量,所减的硬币
        minCoins[cents] = coinCount  
        coinsUsed[cents] = newCoin  # 记录本步骤加的1个硬币
    return minCoins[change]

def printCoins(coinsUsed, change):
    coin = change
    while coin > 0:
        thisCoin = coinsUsed[coin]
        print(thisCoin)
        coin = coin - thisCoin

amnt = 63
clist = [1, 5, 10, 21, 25]
coinsUsed = [0] * (amnt + 1)
coinCount = [0] * (amnt + 1)

print('Making change for', amnt, 'requires')
print(dpMakeChange(clist, amnt, coinCount, coinsUsed), 'coins')
print('they are:')
printCoins(coinsUsed, amnt)
print('The used list is as follows:')
print(coinsUsed)

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值