最大限度地减少转手的硬币数量

时间:2013-03-06 16:10:15

标签: algorithm dynamic-programming coin-change

你有一套硬币5¢,10¢,20¢,50¢,1 $,2 $和每种面额数量有限。当您支付一定金额时,有两种可能性:您支付正确的金额或您支付的金额超过需要,并从职员收到正确的更改。如何最大限度地减少转手的硬币数量(即最小化你给的硬币数量加上你收到的硬币数量)。假设金额总是支付,而职员有无限数量的硬币,而且他总是选择最有效的方式来回报变化。

我认为,为了尽量减少转手的硬币数量,你必须尽量减少你给的硬币数量和你收到的硬币数量。使用通常的硬币更改算法可以最小化收到的硬币数量,但是我不知道如何在给定固定硬币的情况下最小化一组更改。

有关完整的问题说明:UVA Online Judge

3 个答案:

答案 0 :(得分:1)

最小化总和为给定金额的硬币数量是Knapsack Problem的版本。

您的问题是最小化coins(S1) + coins(S2)(您是职员+职员)S1 - S2 = S(您应该支付的金额)。所以你想解决SSmax之间所有变化值的背包问题(知道coins(x)的所有值),然后求解:

min coins(S1) + coins(S2)
under constraints
  S1 - S2 = S
  S1 in [S, Smax]

这可以通过简单的枚举来解决(测试S1的每个可能值)。

现在的问题是确定Smax

的值

不确定这个,但我认为,因为你最大的硬币是2美元,如果你给店员大于S + 2 $的东西,你就不会有任何转移的硬币。所以我的猜测是Smax = S + 2$,但我邀请你多考虑一下。

答案 1 :(得分:0)

我最近在my blog解决了这个问题。这是结局,但为了理解这一点,你必须阅读整篇博客文章:

(define (floupia price coins)
  (if (positive? (modulo price (apply gcd coins)))
      (error 'floupia "infeasible")
      (let ((coins (append coins (map negate coins))))
        (let loop ((n 1))
          (let ((xs (filter (lambda (xs) (= (sum xs) price))
                            (combinations-with-replacement n coins))))
            (if (null? xs) (loop (+ n 1)) xs))))))

基本的想法是首先看看一枚硬币是否可以支付账单,然后是两枚硬币,然后是三枚,依此类推,当你找到最小的解决方案时停止。在每个步骤中考虑所有硬币的所有可能组合,并且替换,以查看是否存在解决方案,将收到的更改视为否定硬币。例如,对于面值为1,3,7,31和153的硬币,以及17的目标价格,有一个5硬币的解决方案,包括支付三个7硬币并收回单个1硬币和3个硬币在改变,但更有效的解决方案是支付一个31硬币并收到两个7硬币的变化。

答案 2 :(得分:0)

这是一个NP-complete问题,它通常使用启发式搜索来解决。相关的启发式方法是首先尝试更大的面额。