Minimum coin change problem with limited amount of coins

我的梦境 提交于 2021-02-08 04:46:56

问题


To be specific, the problem is:
Given array of denominations coins[], array of limit for each coins limits[] and number amount, return minimum number of coins needed, to get the amount, or if it's not possible return null. Additionally fill array change with number of each coin used in the solution.

This is my solution:

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)
            {
                for (int i = 0; i < coins.Length; ++i)
                {
                    if (coinsUsedToAmount[i, j] < limits[i])
                    {
                        int currAmount = j + coins[i];
                        if (currAmount <= amount)
                        {
                            if (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;
    }


But it doesn't work in general.

My issue is that for example in such case:

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 }

Optimal solution is:

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

And my algorithm gives null as a result. In the other words it fails, whenever on some way up I would have to use less optimal solution than it's possible, and then, at the end, I don't have needed coins.
In this example my algorithm gives:
minCoins[132] = 2 (9 + 123),
But it should be minCoins[132] = 4 (2 + 65 + 35 + 30), because then I can use 9 and have 141.

I have been coming back to this problem for a few weeks now and still can't solve it :( I had really seen numerous solutions to similar problems on this and other sites, but none helped me.


回答1:


Friend of mine helped me solve it. The idea is that we go from the amount to 0 and try to use all the nominal of each coins possible - that way we won't end up using certain coins at the beginning, and then we wouldn't have possibility to use them for amount.

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];
}


来源:https://stackoverflow.com/questions/54841133/minimum-coin-change-problem-with-limited-amount-of-coins

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!