硬币变化的变化

时间:2013-01-23 07:03:51

标签: dynamic-programming coin-change

所以典型的硬币变化问题要求你弄清楚你是否可以使用无限的硬币面额x1,x2,...,xn来改变价值v,但我想知道你怎么可能去做使用每个硬币AT MOST一次搞清楚同样的问题?

对于原始问题,我知道你可以迭代值的前缀并查看你是否可以对v-x_i进行更改,但是当它被限制为每个面额最多一个硬币时,我会感到茫然。 / p>

任何让我入门的提示?我可能认为你也可以迭代面额的前缀。虽然不确定......

2 个答案:

答案 0 :(得分:0)

对于变币问题,你可以使用向前或向后复发。在你的陈述中,你向后使用。在这里我将提供一个前进方法,它可以轻松解决UNLIMITED版本和AT-MOST-ONCE版本

假设f是一维布尔数组。 f [i]表示你是否可以改变价值i。最初,f [0] =真,其他等于假。

UNLIMITED版本:

for (int i=1;i<=n;i++)
    for (int j=0;j<v;j++)
        if (f[j])
            f[j+x[i]]=true;

AT-MOST-ONCE版本:

for (int i=1;i<=n;i++)
    for (int j=v-1;j>=0;j--)
        if (f[j])
            f[j+x[i]]=true;

唯一的区别是循环j的顺序。

一个帮助你理解的例子:

假设只有一种硬币花费2.即x [1] = 2。和v = 10

在第一个算法之后,你可以得到f [0] = f [2] = f [4] = f [6] = f [8] = f [10] =真。

但对于第二种算法,你只能得到f [0] = f [2] =真。

答案 1 :(得分:0)

可以使用动态编程解决此问题。

我个人认为绘制表格以帮助导出算法很有用。下面是面额为5、10、2、1的硬币和总价值为V的硬币的示例表。

help table

首先,如果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