正如这个答案中提到的,某些硬币组合可能适合贪婪算法,但不能保证贪婪会给你所有硬币组合的最佳组合。
下面是 Python(一种理想的伪代码语言)中的详尽递归解决方案。
请注意,这为您提供了排列而不是组合,但是,如果您想过滤掉重复项(就组合而言),则在创建列表后进行排序和过滤会很简单。
另请注意,对于较大的金额,这可能会相当可怕。例如,虽然像 27 或 75 这样的输入值不到一秒,但输入 1024 至少需要几分钟才能让我感到无聊并取消它)。
import sys
oldcount = 99999999
lst = []
def recurse (str, amt, count):
global oldcount
global lst
if amt < 0: return
if count > oldcount: return
if amt == 0:
if count < oldcount:
print "====="
lst = []
oldcount = count
if count == oldcount:
lst.append (str)
return
recurse ("%s 19" % str, amt - 19, count + 1)
recurse ("%s 13" % str, amt - 13, count + 1)
recurse ("%s 7" % str, amt - 7, count + 1)
recurse ("%s 1" % str, amt - 1, count + 1)
recurse ("", int (sys.argv[1]), 0)
#for seq in lst: print seq
print "%d permutations" % len (lst)
请注意,对于面额{1, 7, 13, 19}(这种特殊情况),贪心算法是最好的,其“证明”如下(a):
对于 1 到 6 的任何值,你必须使用那么多1硬币,这就是贪心算法给你的。
对于 7 到 12 的任何值,您可以使用那么多1硬币7或少 7 个1硬币。贪心算法为您提供后一种情况,这是正确的,因为最好拿走七个1硬币并添加一个7硬币 - 它会使硬币数量减少六。
对于 13 到 18 的值,您不能使用 a13和 a 7,因为这将是最小值,20因此您会陷入13/1混合或7/1混合(所有1硬币都因与上一段中相同的原因而出局 - 交换 131一个硬币的13硬币是一个巨大的减少)。显然,13 值的最佳投注是单枚13硬币,但 14 可以用一个7/7或13/1(两个硬币)来实现。然后值 15 到 18 只需1添加硬币。
类似地,19 值是单个硬币19,而 20 值可以用19/1或表示13/7。从 21 到 37 的值(就在19/1938 的值之前)19加上前三段的最小组合。
因此,由于选择的值(1并且7是不同的,7/7== 13/1,7/7/7== 19/1/1,13/7==19/1等等),贪心算法工作得很好(我不相信这些值是随机选择的,这太方便了)。
最小硬币计数表如下:
Value Count Possibilities
1 1 1
2 2 1x2
3 3 1x3
4 4 1x4
5 5 1x5
6 6 1x6
7 1 7
8 2 7,1
9 3 7,1x2
:
12 6 7,1x5
13 1 13
14 2 13,1 or 7x2
15 2 13,1x2 or 7x2,1
:
18 6 13,1X5 or 7x2,1x4
19 1 19
20 2 19,1 or 13,7
21 3 19,1x2 or 13,7,1 or 7x3
:
等等。
(a)不是正式的证明,但我很确定我是对的,我会向第一个向我展示反例的人投票 20 个问题/答案(当然,前提是问题和答案不是完全垃圾- 我必须认为它们很有用,以免破坏投票过程)。