你有一套硬币5¢,10¢,20¢,50¢,1 $,2 $和每种面额数量有限。当您支付一定金额时,有两种可能性:您支付正确的金额或您支付的金额超过需要,并从职员收到正确的更改。如何最大限度地减少转手的硬币数量(即最小化你给的硬币数量加上你收到的硬币数量)。假设金额总是支付,而职员有无限数量的硬币,而且他总是选择最有效的方式来回报变化。
我认为,为了尽量减少转手的硬币数量,你必须尽量减少你给的硬币数量和你收到的硬币数量。使用通常的硬币更改算法可以最小化收到的硬币数量,但是我不知道如何在给定固定硬币的情况下最小化一组更改。
有关完整的问题说明:UVA Online Judge
答案 0 :(得分:1)
最小化总和为给定金额的硬币数量是Knapsack Problem的版本。
您的问题是最小化coins(S1) + coins(S2)
(您是职员+职员)S1 - S2 = S
(您应该支付的金额)。所以你想解决S
和Smax
之间所有变化值的背包问题(知道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问题,它通常使用启发式搜索来解决。相关的启发式方法是首先尝试更大的面额。