[英]Bottom-up approach to minimum number of coins for change
我正在构建一种自下而上的方法来解决硬币找零问题。 我必须给出要求进行找零所需的最少硬币数量。 由于给定的面额无法形成该值,因此可能无法给出更改。
例如,如果给定的面额为{4,8},并且他们要求更改为5,那么就不可能给出5。我在下面构造了该程序,它在大多数情况下都可以正常使用,除非无法形成所请求的更改。 例如,当面额仅为{4}且我请求5时,它返回一个为假的。 我该怎么做才能解决这个问题?
这里P表示请求的更改,S是从索引0到S-1的数组denominations []中存储的面额数目。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;
}
}
谢谢您的帮助。
该错误是你没有正确操作时,禁止两者使用当前的硬币, 并没有使用它的情况。 例如,在您的示例情况下会发生这种情况:当i = 1且j = 0时,我们试图不使用任何硬币或仅使用4c硬币来总计1c; 但是我们无法使用4c硬币来做到这一点,也不能没有4c硬币来做到这一点。
在这种情况下,x和y都将被分配为0,并且if (ans == 0) ans = max(x, y);
旨在阻止任何一种可能性时捕获情况,最终错误地将an分配为0。 因此,外循环的后续迭代将“认为”有可能使相应的总和不产生任何硬币,并巧妙地将其加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
:这是一个合理的值,表明a
毛钱不能用硬币的任意组合进行键入<= b
。 理想情况下,为INF
选择的值应具有将其与任何正值相乘或相乘的属性,使它留在INF
,因为那样的话,我们就不必对该算法做任何进一步的调整:对INF
值执行的每个操作都将正确地将其留在INF
。 但是整数算术无法以这种方式工作,因此在将可能是INF
的值添加到某个值之后,我们需要检查是否没有“越过无穷大”并进行修正,如果这样:这就是d[i - denominations[j]][j] + 1
包装在min(INF, ...)
调用中。 (这也是为什么我将INF
定义为小于INT_MAX
-这样就不会发生溢出。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.