硬币改变制造商的解决方案太多了

时间:2014-11-26 03:40:05

标签: java recursive-backtracking

我的计划的目标是将所有可能的变更解决方案输出到给定金额,例如

渴望输出

Change: 9
[1, 1, 1, 1, 5]
[1, 1, 1, 1, 1, 1, 1, 1, 1]

(9 = $ 0.09) 但是我的输出有点不同,我的输出看起来像这样

我的输出

Change: 9
[1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 5]
[1, 1, 1, 5, 1]
[1, 1, 5, 1, 1]
[1, 5, 1, 1, 1]
[5, 1, 1, 1, 1]

正如您所看到的, LITERALLY 为我提供了所有可能的解决方案。我只关心前两个答案。很明显,当要求更大的金额时,这将是一个大问题。所以这是我的问题:基于我的代码,如何将其修复到只显示一个组合的位置?

CODE

import java.io.*;
import java.util.*;
import java.lang.*;

public class homework5 {

 public static int change;

   public static void main(String[] args)
     throws FileNotFoundException { //begin main

     ArrayList<Integer> coinTypes = new ArrayList<Integer>();//array to store
                                                             //coin types
     ArrayList<Integer> answerCoins = new ArrayList<Integer>(); //to contain solutions

     Integer i;
     File f = new File (args[0]);
     Scanner input = new Scanner(f); //initialize scanner
       input.nextLine();
       while(input.hasNextInt()) {
           i = input.nextInt();
           coinTypes.add(i); //add all ints to file
       }
        change = coinTypes.get(coinTypes.size()-1);
        coinTypes.remove(coinTypes.size()-1);
            System.out.println("Change: " + change);

    findChange(change, coinTypes, answerCoins);

   }
    private static void findChange(int change, List<Integer> coinTypes,
                            List<Integer> answerCoins) { //contains means of
                                             //finding the change solutions
        if(change == 0) {
           //base case
          System.out.println(answerCoins);
        }
          else if(change < 0) {
           //if negative it can't be a solution
        } else {
          for(int coin = 0; coin < coinTypes.size(); coin++) {

                 answerCoins.add(coinTypes.get(coin)); //choose
                 findChange(change-coinTypes.get(coin), coinTypes, answerCoins);//explore
                 answerCoins.remove(answerCoins.size()-1);    //un-choose
          }

        }

    }

}

感谢您提供任何和所有答案,请尽量忽略其他任何错误,我想先解决这个问题。谢谢!

2 个答案:

答案 0 :(得分:5)

一个简单的方法是避免创建解决方案,其中您添加到数组末尾的硬币的值小于数组的当前末尾(当然,当数组为空时,总是在第一次迭代时添加) 。这将自然地删除所有这些重复。它很容易实现,因为它不会涉及大量的额外逻辑,只是确保你不会在搜索结果中添加较小的硬币。

它也非常有效:您的递归甚至不会进入这些分支,您也不必进行任何类型的重复搜索。

作为奖励副作用,您所得到的所有解决方案都将包含从最小到最大排序的硬币。 (相反,如果您避免在阵列的末尾添加更大的有价值的硬币,那么您的解决方案将包含从最大到最小的硬币。无论哪种方式,都是优先考虑的问题。)

答案 1 :(得分:2)

您可以将findChange()修改为

private static void findChange(int change, List<Integer> coinTypes,
                        List<Integer> answerCoins, int lastcoin);

lastcoin是指您添加的最后一枚硬币。 在循环中,您不需要迭代coinTypes中的所有硬币。 相反,你只能迭代小于或等于lastcoin的硬币

  for(coin in coins if coin <= lastcoin) { // must in descending order
         answerCoins.add(coinTypes.get(coin)); //choose
         findChange(change-coinTypes.get(coin), coinTypes, answerCoins, coin);//explore
         answerCoins.remove(answerCoins.size()-1);    //un-choose
  }

然后,你只会得到[5,1,1,1,1],并且[1,5,1,1,1]永远不会发生