硬币数量有限时的最小硬币找零问题 [英] Minimum coin change problem with limited amount of coins

查看:201
本文介绍了硬币数量有限时的最小硬币找零问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

具体来说,问题是:
给定面额数组 coins [] ,每个硬币的限额数组 limits [] 和数字 amount ,返回最小值要获得 amount 所需的硬币数量,如果不可能,则返回null.此外,在数组 change 中填写解决方案中使用的每种硬币的编号.

这是我的解决方案:

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.

我的问题是例如:

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] = 2(9 + 123),
但这应该是 minCoins [132] = 4(2 + 65 + 35 + 30),因为这样我就可以使用 9 并具有 141

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.

推荐答案

我的朋友帮助我解决了这个问题.想法是,我们将 amount 更改为 0 ,并尝试尽可能使用每种硬币的名义价值-这样一来,我们最终就不会使用某些硬币了.开始,然后我们将无法使用它们作为金额.

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

这篇关于硬币数量有限时的最小硬币找零问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆