我正在构建一个自下而上的解决硬币变化问题的方法。我必须给出所需更改所需的最少数量的硬币。由于给定的面额不能形成价值,因此可能无法进行更改。
例如,给定的面额是{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;
}
}
感谢您的帮助。
答案 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
的原因 - 这样就不会发生溢出。)