自下而上接近最小硬币数量的变化

时间:2014-08-15 13:26:19

标签: c++ algorithm dynamic-programming coin-change bottom-up

我正在构建一个自下而上的解决硬币变化问题的方法。我必须给出所需更改所需的最少数量的硬币。由于给定的面额不能形成价值,因此可能无法进行更改。

例如,给定的面额是{4,8}并且他们要求改变5然后不可能给出5.我构建了下面的程序并且它适用于大多数情况,除非它不可能形成要求的变更。例如,当面额仅为{4}且我请求5时,它返回一个为假的。我该怎么做才能解决这个问题?

这里P表示要求的变更, S是从索引0到S-1的数组面值[]中存储的面额数.dp是用于初始化为-1的计算的二维数组。

for (int i = 0; i <= P; ++i) {
    for (int j = 0; j < S; ++j) {
        int ans, x, y;

        // Min. no. of coins with current coin
        x = (i - denominations[j] >= 0) ? dp[i - denominations[j]][j] + 1: 0;

        // Min. no. of coins w/o current coin
        y = (j > 0) ? dp[i][j - 1] : 0;

        ans = min(x, y);
        if (ans == 0) ans = max(x, y);
        dp[i][j] = ans;
    }
}

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

如果禁止两者使用当前硬币,不使用它,则您无法正确处理案例。这种情况发生在你的例子中,例如:当i = 1且j = 0时,我们试图使用任何东西或仅使用4c硬币总计1c;但我们不能用4c硬币做到这一点,如果没有4c硬币我们也做不到。

在这种情况下,x和y都将被指定为0,并且设置用于捕捉 的可能性被禁止的行if (ans == 0) ans = max(x, y);会错误地结束将0分配给ans。因此,外循环的后续迭代将“认为”可以使得总共没有任何硬币的相应总和,并轻率地将其加1,为您的示例提供1的错误答案。

我认为最干净的解决方法是选择一个不同于0的不同标记值来表示“此操作是不可能的,不应该被考虑”。由于您将两个可能的操作与min()组合在一起,因此非常高的值非常适合:

#define INF (INT_MAX-1)   // Or anything higher than the biggest sensible answer

for (int i = 0; i <= P; ++i) {
    for (int j = 0; j < S; ++j) {
        int ans, x, y;

        // Min. no. of coins with current coin
        x = (i - denominations[j] >= 0) ? min(INF, dp[i - denominations[j]][j] + 1) : INF;

        // Min. no. of coins w/o current coin
        y = (j > 0) ? dp[i][j - 1] : INF;

        ans = min(x, y);
        dp[i][j] = ans;
    }
}

注意ans = min(x, y);行现在如何在没有进一步工作的情况下给出正确的答案,包括INF的情况,因为x和y都是INF

更微妙的一点是,当我们在计算过程中读取某些dp[a][b]时,该值可以为INF :这是合法值,表示不能使用&lt; = a类型的任何硬币组合制作b美分。理想情况下,为INF选择的值将具有将其添加或乘以任何正值的属性,使其保持在INF,因为那时我们不必对此算法进行任何进一步调整:我们对INF值执行的操作会正确地将其保留在INF。但是整数算术不能那样工作,所以在向INF的值添加某些内容后,我们需要检查我们是否已经“超越无限”并修复它,如果是这样的话:那就是为什么{{ 1}}包含在d[i - denominations[j]][j] + 1调用中。 (这也是我将min(INF, ...)定义为小于INF的原因 - 这样就不会发生溢出。)