当前位置: 首页 > 知识库问答 >
问题:

硬币数量有限的最小硬币更换问题

杜君浩
2023-03-14

具体而言,问题是:
给定面额数组<代码>硬币[],每个硬币的限制数组<代码>限制[]和数量<代码>金额,返回所需的最小硬币数量,以获取<代码>金额,或者如果不可能,返回空值。另外,用溶液中使用的每个硬币的数量填充数组change

这是我的解决方案:

public static int? Dynamic(int amount, int[] coins, int[] limits, out int[] change)
{
    int[] minCoins = new int[amount + 1];
    int[,] coinsUsedToAmount = new int[coins.Length, amount + 1];

    minCoins[0] = 1;
    for (int j = 0; j < amount; ++j)
    {
        if (minCoins[j] == 0)
        {
            continue;
        }
        
        for (int i = 0; i < coins.Length; ++i)
        {
            if (coinsUsedToAmount[i, j] >= limits[i])
            {
                continue;
            }
            
            int currAmount = j + coins[i];
            if (currAmount <= amount 
                && (minCoins[currAmount] == 0 
                    || minCoins[currAmount] > minCoins[j] + 1))
            {
                minCoins[currAmount] = minCoins[j] + 1;
                for (int k = 0; k < coins.Length; ++k) 
                {
                    coinsUsedToAmount[k, currAmount] = coinsUsedToAmount[k, j];
                }
                coinsUsedToAmount[i, currAmount] += 1;
            }
        }
    }

    if (minCoins[amount] == 0)
    {
        change = null;
        return null;
    }

    change = new int[coins.Length];
    for(int i = 0; i < coins.Length; ++i)
    {
        change[i] = coinsUsedToAmount[i, amount];
    }

    return minCoins[amount] - 1;
}

但它一般不起作用。

我的问题是,例如,在这种情况下:

amount = 141, 
coins = new int[] { 2, 137, 65, 35, 30, 9, 123, 81, 71 }                                                                                  
limits = new int[] { 1, 1, 1, 1, 1, 1, 1, 1, 1 }

最佳解决方案是:

 change = new int[] { 1, 0, 1, 1, 1, 1, 0, 0, 0 }

并且我的算法给出null作为结果。换句话说,它失败了,每当在某种情况下,我将不得不使用比可能的更少的最优解,然后,在最后,我没有必要的硬币。

所以,在这个例子中,我的算法在下面的步骤中犯了一个错误:

minCoins[132] = (9 + 123) // 2 coins

但它应该是:

minCoins[132] = (2 + 65 + 35 + 30) // 4 coins

因为这样我就可以使用9和141。

我已经回到这个问题上几个星期了,但我仍然无法解决它。我在这个网站和其他网站上看到了许多类似问题的解决方案,但没有一个对我有帮助。

共有1个答案

万俟财
2023-03-14

我的朋友帮我解决了这个问题。我们的想法是从数量0,并尽可能使用每种硬币的所有面值-这样我们就不会在开始时使用某些硬币,也就不可能使用它们来表示金额。

/// <summary>
///  Method used to resolve minimum change coin problem
///  with constraints on the number of coins of each type.
/// </summary>
/// <param name="amount">Amount of change to make, e.g. 13</param>
/// <param name="coins">Available types of coins, e.g. {1, 2, 3, 5}</param>
/// <param name="limits">Number of available coins of specific type, e.g. {1, 5, 3, 2}</param>
/// <param name="change">Number of coins of each type used to make the change, e.g. {0, 0, 1, 2}</param>
/// <returns>
///  Minimal number of coins needed to make the change 
///  (equal to sum of change array entries), e.g. 3
/// </returns>
/// <remarks>
///  coins[i]  - nominal value of the coin of i-th type
///  limits[i] - number of available coins of i-th type (denomination)
///  change[i] - number of coins of i-th type used in the solution
/// 
///  If available `coins` and `limits` does not allow to make provided `amount` of change 
///  then `change` should be set to `null`, and method should also return `null`.
///
///  Tips/requirements:
///   The size of work memory of the algorithm should (must) be 
///   proportional to the value of product: `amount*(coins.Length)` 
///   (that is O(amount*(coins.Length))
/// </remarks>
public static int? Dynamic(int amount, int[] coins, int[] limits, out int[] change)
{
        int[][] coinsUsed = new int[amount + 1][];
        for (int i = 0; i <= amount; ++i)
        {
            coinsUsed[i] = new int[coins.Length];
        }

        int[] minCoins = new int[amount + 1];
        for (int i = 1; i <= amount; ++i)
        {
            minCoins[i] = int.MaxValue - 1;
        }

        int[] limitsCopy = new int[limits.Length];
        limits.CopyTo(limitsCopy, 0);

        for (int i = 0; i < coins.Length; ++i)
        {
            while (limitsCopy[i] > 0)
            {
                for (int j = amount; j >= 0; --j)
                {
                    int currAmount = j + coins[i];
                    if (currAmount <= amount)
                    {
                        if (minCoins[currAmount] > minCoins[j] + 1)
                        {
                            minCoins[currAmount] = minCoins[j] + 1;

                            coinsUsed[j].CopyTo(coinsUsed[currAmount], 0);
                            coinsUsed[currAmount][i] += 1;
                        }
                    }
                }

                limitsCopy[i] -= 1;
            }
        }

        if (minCoins[amount] == int.MaxValue - 1)
        {
            change = null;
            return null;
        }

        change = coinsUsed[amount];
        return minCoins[amount];
}
 类似资料:
  • 所以我对编码不熟悉,我得到了一个任务,我需要做一个程序,用四分之一、一角、五分和一美分给不到一美元的零钱。然而,作业希望程序打印所需的最低硬币数量(例如,如果我输入58美分,那么输出应该是“2个25美分,1个镍和3个便士”,而不是“2个25美分,0个10美分,1个镍和3个便士”。本质上,如果没有某种硬币,那么程序就不应该打印它)。我一直在想如何制作它,这样程序就不会打印任何不必要的硬币。 这就是我

  • 动态规划变更问题(有限硬币)。我正在尝试创建一个以以下内容作为输入的程序: 输出: 输出应该是大小为1的数组,其中每个单元格代表我们需要改变单元格索引量的最佳硬币数。 假设数组的单元格位于index: 5,内容为2。这意味着为了给出5(INDEX)的变化,您需要2(单元格的内容)硬币(最佳解决方案)。 基本上,我需要这个视频的第一个数组的输出(C[p])。这与有限硬币的大区别是完全相同的问题。链接

  • 问题:https://leetcode.com/problems/coin-change/ 解决方案:https://repl.it/@Stylebender/HatefulAliceBlueTransverse#index.js 我理解从“按钮式”构建dp阵列解决方案的一般概念流程,但我只是想知道关于第10行: dp[i]=数学。最小值(dp[i],1 dp[i-硬币[j]]; 当你选择当前的第

  • 我们得到了一套面额和总额。 每种面额的无限硬币都可以买到 所有面额都是5的幂 我们必须找到总数所需的最低硬币数量。 我想知道解决方案背后的逻辑。提前感谢。

  • 我有以下问题: 给定一个目标大小N和一些随机生成的硬币的一些面额,这些硬币存储在数组面额[]中,使用动态规划检查是否存在一个最优解决方案,该方案将使用最少的硬币填充整个目标。 这是硬币兑换问题的一个典型例子,但与现实生活中的货币不同,在现实生活中,每种面额都是经过仔细挑选的,因此可以匹配任何目标。事实并非如此。 我熟悉硬币兑换问题中使用的算法,以及如何构造一个动态规划数组来找到解决方案,但我首先如

  • 我正在尝试打印最小数量的硬币来进行更改,如果不可能,请打印-1 在这段代码中,变量int[]c(硬币数组)有面额,我可以用它来计算总金额。 INT总有总和,我需要拿出使用硬币(无限供应) 对于Sum:4759和Array:{3190836},正确的输出是:59,我的输出是:60 代码中有什么错误? 下面是我的递归解决方案,尝试在DP解决方案中应用相同的逻辑。这里的逻辑似乎也有问题。对于相同的输入,