精确变更算法

编程入门 行业动态 更新时间:2024-10-28 20:23:14
本文介绍了精确变更算法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我正在尝试编写一种算法,以检查在有限数量的不同值的硬币(特别是Quarters,Dimes,Nickels和Pennies)的情况下是否有可能实现零钱。我已经看到了许多建议的解决方案包括此处的堆栈溢出以及 freeCodeCamp ,但是这两种解决方案都有相同的问题,有时会产生

I'm trying to write an algorithm that checks if it is possible to get exact change given a limited number of coins of different values, specifically Quarters, Dimes, Nickels, and Pennies. I have seen many proposed solutions including here on stack overflow as well as one from freeCodeCamp but both of these solutions share the same problem in that sometimes produce false negatives.

注意:这不是产生变化的问题,因为我对无限池中的最小硬币数量不感兴趣,即使现有池可以支持确切数量的硬币也是如此。

NOTE: this is not the Change-making problem as I am not interested in the minimum number of coins from an infinite pool, just if the existing pool can support an exact quantity.

我见过的常用算法如下:

The algorithm I have seen commonly used is as follows:

  • 在池中找到价值低于目标金额的最高硬币
  • 减去池中的硬币之一,然后从目标金额中减去其值
  • 继续,直到目标金额为0(返回true或所需硬币列表),或者直到没有可用币值小于目标的硬币(返回false)

但是这种方法存在一个问题:如果解决方案需要高价值的低面额硬币,即使可能存在有效的解决方案,也会返回false。

But there is a problem with this approach: If a solution requires a high value of low denomination coins, it will return false even though there may be a valid solution.

这里是该算法的一些代码(从前面链接的堆栈溢出文章中适应了我的目的,因此可能很乱)

Here is some code of this algorithm (adapted for my purposes from that stack overflow article linked earlier so it may be messy)

values = [25, 10, 5, 1] def exact_change(target_amount, L, ret = None): if ret == None: ret = [0] * len(L) for i in range(len(L)): if L[i] == 0: continue if values[i] == target_amount: ret[i] += 1 return ret else: if values[i] < target_amount: L[i] -= 1 ret[i] += 1 return exact_change(target_amount-values[i], L, ret) else: return False print(exact_change( 48, [1, 2, 6, 3] )) # [1, 2, 0, 3] correct print( exact_change( 45, [2, 1, 1, 4] )) # False correct print(exact_change( 285, [100, 10, 10, 100] )) # [11, 1, 0, 0] correct print(exact_change( 65, [2, 4, 1, 0] )) # [2, 1, 1, 0] correct print(exact_change( 65, [2, 6, 0, 0] )) # False incorrect! [1, 4, 0, 0] would work

如果您从要么先寻找价值较低的硬币。我只是还没有找到更好的算法,还是一个开放的问题?我可以通过检查将产生目标值的硬币的每种组合,并查看给定的池是否可以实现这种组合,但对于较大的值似乎效率低下,来蛮力解决问题。

This approach doesn't work if you start by looking for lower valued coins first either. Is there a better algorithm I simply haven't found yet or is this an open problem? I can brute force a solution by checking each combination of coins that would produce the target value and seeing if that combination is possible with the given pool but that seems inefficient for large values.

推荐答案

您当前的算法存在的问题是,它只能尝试递归一次。无论该递归找到了什么(有效的解决方案或失败),该结果都会无条件返回。尽管还有其他一些算法可能会有所不同,但是您可以对当前代码进行少量更改以通过添加回溯来使其正常工作。

The problem your current algorithm has is that it only ever attempts to recurse once. Regardless of what that recursion finds (either a valid solution, or a failure), that result is returned unconditionally. While there are some other algorithms that would work differently, you can make a small change to your current code to make it work by adding backtracking.

回溯步骤在每次执行之后进行递归。首先,您检查递归是否成功(例如,找到了有效的结果)。如果是这样,您将像平常一样返回该结果。但是,如果操作失败,则需要撤消对问题状态所做的更改(在这种情况下,撤消对 L 和 ret的更改) ,然后继续尝试另一种硬币面额。

The backtracking step happens after each recursion. First you check if the recursion was successful (e.g. it found a valid result). If so, you return that result like normal. However, if it was unsuccessful, you need to undo the changes you made to the problem state (in this case, undo the changes to L and ret, and then go on to try another coin denomination.

虽然您的代码还有另一个问题,您的代码没有任何办法避免每次函数递归时都检查相同的起始面额,因此对于某些输入,您将一遍又一遍地尝试相同的不良解决方案。一种避免重新检查相同硬币的方法是将起始索引与其他参数一起传递,并且

There's another issue with your code though. Your code doesn't have any way to avoid checking the same starting denominations every time your function recurses, so for some inputs you'll keep trying the same bad solutions over and over. A way to avoid reexamining the same coins is to pass a start index along with the other arguments, and not look at the coins before that index at all.

def exact_change(target_amount, L, start_index=0, ret=None): if ret == None: ret = [0] * len(L) for i in range(start_index, len(L)): # start at start_index if L[i] == 0: continue if values[i] == target_amount: ret[i] += 1 return ret elif values[i] < target_amount: # no need for the extra indentation of else: if ...: L[i] -= 1 ret[i] += 1 result = exact_change(target_amount-values[i], L, i, ret) # pass i as start_index if result: # check the result to make sure it was successful before returning return result L[i] += 1 # backtrack if it was not ret[i] -= 1 else: return False # None might be a more natural value to return here

请注意,如果需要,可以避免在递归步骤中修改 L (并且需要在回溯时撤消更改)。只需将 L [i] == 0 测试更改为 L [i] == ret [i] 。

Note that if you wanted to, you could avoid modifying L during the recursive step (and needing to undo the change when backtracking). Just change the L[i] == 0 test to L[i] == ret[i] instead.

更多推荐

精确变更算法

本文发布于:2023-08-01 09:00:27,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1267067.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:算法   精确

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!