28、数据结构与算法Python:找零兑换问题的动态规划解法

找零兑换:动态规划解法

中间结果记录可以很好解决找零兑换问题

实际上, 这种方法还不能称为动态规划,而是叫做“memoization(记忆化/函数值缓存) ”的技术提高了递归解法的性能

动态规划算法采用了一种更有条理的方式来得到问题的解

找零兑换的动态规划算法从最简单的“1分钱找零”的最优解开始, 逐步递加上去, 直到我们需要的找零钱数

在找零递加的过程中, 设法保持每一分钱的递加都是最优解, 一直加到求解找零钱数, 自然得到最优解

递加的过程能保持最优解的关键是, 其依赖于更少钱数最优解的简单计算, 而更少钱数的最优解已经得到了。

问题的最优解包含了更小规模子问题的最优解, 这是一个最优化问题能够用动态规划策略解决的必要条件。

originalamount找零兑换问题具体来说就是:
*

找零兑换:动态规划算法

采用动态规划来解决11分钱的兑换问题

从1分钱兑换开始,逐步建立一个兑换表
*

计算11分钱的兑换法, 我们做如下几步:

1、 首先减去1分硬币,剩下10分钱查表最优解是1;
2、 然后减去5分硬币,剩下6分钱查表最优解是2;
3、 最后减去10分硬币,剩下1分钱查表最优解是1;

通过上述最小值得到最优解: 2个硬币

*

找零兑换:动态规划算法代码

def dpMakeChange(coinValueList, change, minCoins):
    # 从1分开始到change逐个计算最好硬币数
    for cents in range(1, change+1):
        # 1. 初始化一个最大值
        coinCount = cents
        # 2. 减去每个硬币,向后查最少硬币数,同时记录总的最少数
        for j in [c for c in coinValueList if c <= cents]:
            if minCoins[cents-j] + 1 < coinCount:
                coinCount = minCoins[cents - j] + 1
        # 3. 得到当前最少硬币数,记录到表中
        minCoins[cents] = coinCount
    # 返回最后一个结果
    return minCoins[change]

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

*

找零兑换:动态规划算法扩展

我们注意到动态规划算法的dpMakeChange并不是递归函数

虽然这个问题是从递归算法开始解决,但最终我们得到一个更有条理的高效非递归算法

动态规划中最主要的思想是:

从最简单情况开始到达所需找零的循环其每一步都依靠以前的最优解来得到本步骤的最优解,直到得到答案。

前面的算法已经得到了最少硬币的数量,但没有返回硬币如何组合

扩展算法的思路很简单, 只需要在生成最优解列表同时跟踪记录所选择的那个硬币币值即可

在得到最后的解后, 减去选择的硬币币值, 回溯到表格之前的部分找零, 就能逐步得到每一步所选择的硬币币值

def dpMakeChange(coinValueList, change, minCoins, coinsUsed):
    # 从1分开始到change逐个计算最好硬币数
    for cents in range(1, change+1):
        # 1. 初始化一个最大值
        coinCount = cents
        # 初始化一下新加硬币
        newCoin = 1
        # 2. 减去每个硬币,向后查最少硬币数,同时记录总的最少数
        for j in [c for c in coinValueList if c <= cents]:
            if minCoins[cents-j] + 1 < coinCount:
                coinCount = minCoins[cents - j] + 1
                newCoin = j
        # 3. 得到当前最少硬币数,记录到表中
        minCoins[cents] = coinCount
        # 记录本步骤加的1个硬币
        coinsUsed[cents] = newCoin
    # 返回最后一个结果
    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)
coinsCount = [0] * (amnt + 1)

print("Making change for", amnt, "requires")
print(dpMakeChange(clist, amnt, coinsCount, coinsUsed), "coins")
print("They are:")
printCoins(coinsUsed, amnt)
print("The used list is as follows:")
print(coinsUsed)

*

版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: