这个问题可以用动态规划来解决。
我个人觉得画一张表格来帮助推导算法很有用。下面是面额为 5、10、2、1 和总价值 V 的硬币的棕褐色示例表。
首先,如果 v = 0,我们为所有 i 初始化表为 True(对于零值,更改总是正确的)
For i: 0-> n D(v,0) = true
然后我们遍历表,逐行(从左到右)和逐列(从上到下)
For v: 1-> V
For i: 0-> n
可以观察到,我们能够在两种情况下给出值 v 和硬币 xi 的变化:
- 我们能够为价值 v - xi 和之前的硬币 x(i-1) 提供零钱
D(v,i) = true if D(v-xi, i-1) = true
这种情况的示例包括硬币 xi=5(第二列)和 v=5 或硬币 xi=1(最后一列)和 v=6
- 我们能够为以前的硬币和相同的价值提供零钱。 (如果价值是 5 并且我们已经有一个硬币 5,那么我们之后有多少硬币并不重要 - 我们已经给了一个完整的零钱。)
D(v,i) = true if D(v, i-1) = true
这种情况的示例是第 5 行。
在上述情况均不适用的情况下,我们无法提供全部更改,D(v,i) 为假。最终的解决方案是总值V和索引n对应的表格元素。
总结一下:
For i: 0-> n D(v,0) = true
For v: 1-> V
For i: 0-> n
D(v,i)= D(v, i-1) V D(v-xi, i-1 )
else D(v,i) = false;
return D(V, n)
repl 中完全编码解决方案的链接:https://repl.it/@majakudlicka/CoinChangeVariation