【问题标题】:Least Coin Used Algorithm Java最少硬币使用算法 Java
【发布时间】:2015-03-10 09:02:29
【问题描述】:

我被硬币面额的问题困住了。

我试图找出构成 5.70 美元(或 570 美分)的最少硬币数量。例如,如果硬币数组是 {100,5,2,5,1}(100 x 10c 硬币、5 x 20c、2 x 50c、5 x $1 和 1 x $2 硬币),那么结果应该是 { 0,1,1,3,1} 目前硬币阵列将包含相同面额($2、$1、50c、20c、10c)

public static int[] makeChange(int change, int[] coins) {

    // while you have coins of that denomination left and the total
    // remaining amount exceeds that denomination, take a coin of that
    // denomination (i.e add it to your result array, subtract it from the
    // number of available coins, and update the total remainder). –

    for(int i= 0; i< coins.length; i++){
    while (coins[i] > 0) {

        if (coins[i] > 0 & change - 200 >= 0) {

            coins[4] = coins[4]--;
            change = change - 200;

        } else 

        if (coins[i] > 0 & change - 100 >= 0) {

            coins[3] = coins[3]--;
            change = change - 100;

        } else

        if (coins[i] > 0 & change - 50 >= 0) {

            coins[2] = coins[2]--;
            change = change - 50;

        } else

        if (coins[i] > 0 & change - 20 >= 0) {

            coins[1] = coins[1]--;
            change = change - 20;

        } else

        if (coins[i] > 0 & change - 10 >= 0) {

            coins[0] = coins[0]--;
            change = change - 10;

        }
    }

    }
    return coins;

}

我被困在如何从硬币数组中扣除值并返回它。

编辑:新代码

【问题讨论】:

  • 这是一个(未优化的)算法:对于每个面额,当您剩余该面额的硬币并且总剩余金额超过该面额时,取出该面额的硬币(即将它添加到您的结果数组中,从可用硬币的数量中减去它,然后更新总余数)。
  • 你的方向不对,你有一个NP-Complete问题,并且没有已知的多项式解决方案。但是,对于每个硬币都有无穷大的情况,有一个伪多项式解,这被称为Change Making Problem。我不知道你是否可以调整每个硬币数量有限的伪多项式解。
  • 请检查我的编辑家伙
  • @user3353723 你一直在说“有人发布一些代码”。您想了解如何解决问题吗?
  • 如果不同种类的硬币数量有限,我认为贪婪是行不通的,即使面额是规范。让我换个说法:如果对每种硬币的数量施加限制,我不认为所有规范面额都可以通过贪婪来最佳解决。它可能适用于一组 OPs 面额,以及 canonical 面额的子集。

标签: java int


【解决方案1】:

蛮力解决方案是尝试使用最高面额的硬币的可用数量(当你用完时停止或金额将变为负数),并为其中的每一个递归解决剩余金额的较短列表排除该面额,并选择其中的最小值。如果基本情况是 1c 问题总是可以解决的,基本情况是return n 否则是n/d0d0 代表最低面额),但必须注意在不均匀时返回较大的值可分割,因此优化可以选择不同的分支。记忆是可能的,并通过剩余金额和下一个尝试的面额进行参数化。所以备忘录表的大小是O(n*d),其中n是起始金额,d是面额数量。

所以问题可以在伪多项式时间内解决。

【讨论】:

    【解决方案2】:

    wikipedia link 没有详细说明如何确定像您这样的贪心算法是否有效。此CS StackExchange question 中链接了更好的参考。本质上,如果硬币系统是规范,贪心算法将提供最佳解决方案。那么,[1, 2, 5, 10, 20] 是规范的吗? (使用 10 美分作为单位,因此序列从 1 开始)

    根据this article,5 币系统是-规范的当且仅当它完全满足以下条件之一:

    • [1, c2, c3] 不规范([1, 2, 5] 为假)
    • 不能写成 [1, 2, c3, c3+1, 2*c3](对于 [1, 2, 5, 10, 20] 为真)
    • greedyAnswerSize((k+1) * c4) > k+1 with k*c4

    因此,由于贪心算法不会提供最佳答案(即使它提供了,我怀疑它是否适用于有限的硬币),你应该尝试动态编程或一些开明的回溯:

    import java.util.HashSet;
    import java.util.PriorityQueue;
    
    public class Main {
    
        public static class Answer implements Comparable<Answer> {
            public static final int coins[] = {1, 2, 5, 10, 20};
    
            private int availableCoins[] = new int[coins.length];
            private int totalAvailable;
            private int totalRemaining;
            private int coinsUsed;
    
            public Answer(int availableCoins[], int totalRemaining) {
                for (int i=0; i<coins.length; i++) {
                    this.availableCoins[i] = availableCoins[i];
                    totalAvailable += coins[i] * availableCoins[i];
                }
                this.totalRemaining = totalRemaining;
            }
    
            public boolean hasCoin(int coinIndex) { 
                return availableCoins[coinIndex] > 0; 
            }
    
            public boolean isPossibleBest(Answer oldBest) {
                boolean r = totalRemaining >= 0
                    && totalAvailable >= totalRemaining
                    && (oldBest == null || oldBest.coinsUsed > coinsUsed);
                return r;
            }
    
            public boolean isAnswer() {
                return totalRemaining == 0;
            }
    
            public Answer useCoin(int coinIndex) {
                Answer a = new Answer(availableCoins, totalRemaining - coins[coinIndex]);
                a.availableCoins[coinIndex]--;
                a.totalAvailable = totalAvailable - coins[coinIndex];
                a.coinsUsed = coinsUsed+1;
                return a;
            }
    
            public int getCoinsUsed() {
                return coinsUsed;
            }
    
            @Override
            public String toString() {
                StringBuilder sb = new StringBuilder("{");
                for (int c : availableCoins) sb.append(c + ",");            
                sb.setCharAt(sb.length()-1, '}');
                return sb.toString();
            }
    
            // try to be greedy first
            @Override
            public int compareTo(Answer a) {
                int r = totalRemaining - a.totalRemaining;
                return (r==0) ? coinsUsed - a.coinsUsed : r;
            }
        }        
    
        // returns an minimal set of coins to solve
        public static int makeChange(int change, int[] availableCoins) {
            PriorityQueue<Answer> queue = new PriorityQueue<Answer>();
            queue.add(new Answer(availableCoins, change));
            HashSet<String> known = new HashSet<String>();
            Answer best = null;
            int expansions = 0;
            while ( ! queue.isEmpty()) {
                Answer current = queue.remove();            
                expansions ++;
                String s = current.toString();
                if (current.isPossibleBest(best) && ! known.contains(s)) {
                    known.add(s);
                    if (current.isAnswer()) {
                        best = current;
                    } else {
                        for (int i=0; i<Answer.coins.length; i++) {
                            if (current.hasCoin(i)) {
                                queue.add(current.useCoin(i));
                            }
                        }
                    }
                }
            }
            // debug
            System.out.println("After " + expansions + " expansions");
            return (best != null) ? best.getCoinsUsed() : -1;
        }
    
        public static void main(String[] args) {
            for (int i=0; i<100; i++) {
                System.out.println("Solving for " + i + ":"
                    + makeChange(i, new int[]{100,5,2,5,1}));
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      你走错方向了。该程序不会为您提供最佳解决方案。要获得最佳解决方案,请使用此处实施和讨论的动态算法。请访问以下几个链接:

      1. link 1
      2. link 2
      3. link 3

      【讨论】:

      • 这些链接解决了不同的问题。这里每种硬币的数量都是有限的。
      • 我建议他看看这些链接以获得想法。我还没有告诉他的问题有答案代码。投反对票,它....
      • 嗯,我认为规则是,如果您没有实际答案,请坚持发表评论。
      • 由于少于 50 个 repo。我无法评论其他帖子。最少 50 是必需的。
      • 大声笑,所以回答不同的问题,但是是的,这方面的东西有点糟糕——抱歉,我没有注意到。
      猜你喜欢
      • 2020-05-09
      • 1970-01-01
      • 1970-01-01
      • 2021-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-05
      • 1970-01-01
      相关资源
      最近更新 更多