【问题标题】:Recursion gives correct answer for minimum Coin Change but dynamic programming gives wrong answer递归给出了最小硬币变化的正确答案,但动态编程给出了错误的答案
【发布时间】:2016-02-02 00:21:05
【问题描述】:

我试图解决这个问题好几个小时,但我无法直观地思考它。对此有一种心理障碍。经过多次尝试,对于存在解决方案的情况,我能够得到正确的递归解决方案。所以我有以下问题:

  1. 递归程序正在为存在解决方案的输入提供正确的解决方案。如何在解决方案不存在的情况下返回“不存在解决方案”。 Ex for Coins [3,10],没有解决方案来改变 17。

  2. DP 程序中的错误是什么?我尝试使用记忆技术创建字典并为其添加值,但程序无法正常运行。

import math
def findMinCoins(denomination, change):
    #recursive solution
    minCoins = change
    if(len(denomination )== 0 or change ==0): #when there are no coins or change is 0
        return 0
    elif(change in denomination):
        return 1
    elif(change < min(denomination)):
        return float("inf")
    else:
        for i in denomination:
            if(i<=change):
                numCoins = 1 + findMinCoins(denomination, change - i)
                if(numCoins < minCoins):
                    minCoins = numCoins
    return minCoins

c = [3,10]
d = 30

print findMinCoins(c,d)

现在是 DP 解决方案。

import math
coinsDict = {}

def findMinCoins(denomination, change):
    minCoins = change
    if(len(denomination )== 0 or change ==0):
        return 0
    elif(change in denomination):
        return 1
    elif(change < min(denomination)):
        return float("inf")
    else:
        for i in denomination:
            if (coinsDict.get(change)):
                print 'dictionaty',change, coinsDict.get(change)
                return coinsDict[change]
            elif(i<=change):
                numCoins = 1 + findMinCoins(denomination, change - i)
                if(numCoins < minCoins):
                    minCoins = numCoins
                    print change, numCoins
                    coinsDict[change] = numCoins

    return minCoins

c = [3,10]
d = 30

print findMinCoins(c,d)

【问题讨论】:

  • 欢迎来到 StackOverflow。请阅读并遵循帮助文档中的发布指南。 Minimal, complete, verifiable example 适用于此。在您发布代码并准确描述问题之前,我们无法有效地帮助您。 “无法正常工作”不是问题描述。显示您的输出和您运行的逻辑跟踪。
  • @Prune 在 DP 程序中输入硬币 = [3,10] 和零钱 = 30。输出是 10 个硬币,但应该是 3 个硬币,因为 [10,10,10] 是最小数字所需的硬币。我认为问题存在是因为我首先将硬币 3 添加到字典中。现在,当程序为硬币 10 递归调用自身时,它会检查是否存在特定更改的值。所以它也使用 3 的值来表示 10。

标签: python recursion dynamic-programming


【解决方案1】:

问题在于您使用备忘录的方式。如果您找到了针对特定更改量的解决方案,您永远不会认为可能有更好的解决方案。看逻辑

    if (coinsDict.get(change)):
        print 'dictionaty',change, coinsDict.get(change)
        return coinsDict[change]
    elif(i<=change):
        numCoins = 1 + findMinCoins(denomination, change - i)

在你第一次通过递归时,你一直走下去,发现你可以用 10 个 3 的硬币处理 30 美分。然后你放松回到堆栈的顶部,然后用 10 美分的硬币再试一次...但是在您费心寻找解决方案之前,上述逻辑说:“我已经知道如何处理 30 美分:返回 10 个硬币。”它永远不会探索涉及其他数量的解决方案。

如果您颠倒检查面额的顺序,您将得到所需的解决方案。确保您尝试其他测试用例:您应该会发现这种简单的修复不足以修复您的逻辑。例如,尝试

c = [3, 11, 13] d = 22

如果你找不到更好的解决方案,你会找到 13、3、3、3 的 4 硬币解决方案,而错过 11、11 的答案。

【讨论】:

  • 谢谢修剪。我错误地在 For 循环中的字典中添加了元素。当我在返回 minCoins 上方的 for 循环外写“coinsDict[change] = numCoins”时,程序显示输入硬币 [3,10] change = 30 的正确输出 3。
  • 太棒了!它是否也处理 ([3, 11, 13], 22) 的情况?
  • Yes 瞬间打印 2 个。你能建议我如何编辑代码,所以当我遇到像 ([3, 11, 13], 23) 这样不存在解决方案的情况时,它返回 0。错误地在上面写了“coinsDict [change] = numCoins”而不是“coinsDict [更改] = minCoins"
  • 两种可能性之一: (1) 编写一个调用 findMinCoins 的包装函数。它的唯一目的是检查返回值:如果它包含“inf”,则返回0而不是返回给主程序; (2) 修改返回失败的逻辑。首先,返回一个信号值而不是“inf”(当你的逻辑的其余部分需要一个整数时返回一个字符串并不酷)。其次,如果您有 numCoins = 1 + findMinCoins...,请将其拆分以检查返回值并将故障传播回顶层。够清楚吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-17
相关资源
最近更新 更多