Java硬币回溯

Java硬币回溯,java,backtracking,Java,Backtracking,下午好 我目前正在开发一个程序,该程序应该使用回溯算法来找到达到一定数量所需的硬币总数的解决方案 程序的基本布局如下所示 User is prompted for an amount (ie. 123) int amount = input.nextInt(); User is prompted for number of coins (ie. 6) int numCoins = input.nextInt(); User is prompted for coin values (ie.

下午好

我目前正在开发一个程序,该程序应该使用回溯算法来找到达到一定数量所需的硬币总数的解决方案

程序的基本布局如下所示

User is prompted for an amount (ie. 123)
 int amount = input.nextInt();

User is prompted for number of coins (ie. 6)
 int numCoins = input.nextInt();

User is prompted for coin values (ie. 2, 4, 32, 51, 82)
 int[] array = new array[] {2, 4, 32, 51, 82};
根据这些信息,我将开发一种回溯算法来输出解决方案。
我试图查找回溯信息,但没有实际效果。对我来说这一切似乎都很不清楚 我想从算法开始

感谢您的帮助

编辑

这是我目前正在做的。。。它目前不工作

public class coins
{

public static int[] coinValues;
public static int currentAmount = 0;

public static void main(String[] args)
{
    ArrayList<Integer> temp = new ArrayList<>();
    Scanner input = new Scanner(System.in);

    System.out.println("Please enter the amount: ");
    int amount = input.nextInt();

    System.out.println("Please enter the number of coins: ");
    int numCoins = input.nextInt();
    coinValues = new int[numCoins];

    for (int i = 0; i < numCoins; i++)
    {
        System.out.println("Please enter coin value of " + i + " :");
        int value = input.nextInt();
        coinValues[i] = value;
    }

    for (int i = 0; i < coinValues.length; i++)
    {
        System.out.print("Coin Value: " + i + " " + coinValues[i] + "\n");
    }

    tryThis(temp, amount);

    for (int i = 0; i < temp.size(); i++)
    {
        System.out.println(temp.get(i) + " " + " ");
    }
}

public static ArrayList<Integer> tryThis(ArrayList<Integer> list, int amount)
{
    if (isValid(list, amount) == false)
    {
        while (amount > currentAmount && (amount > 0))
        {
            for (int i = 0; i < coinValues.length; i++)
            {
                for (int k = coinValues.length - 1; k > 0; k--)
                {
                    list.add(coinValues[k]);
                    int currentCoin = list.get(i);


                    if (amount > currentAmount)
                    {
                        amount = amount - currentCoin;
                        System.out.println("Amount: " + amount);
                    }

                    tryThis(list, amount);
                }
            }
        }
    }


    return new ArrayList<>();
}

public static boolean isValid(ArrayList list, int amount)
{
    boolean keepGoing = true;
    if (amount > currentAmount)
    {
        return keepGoing = false;
    }
    else
    {
        return keepGoing;
    }
}
}
公共等级硬币
{
公共静态int[]值;
公共静态int currentAmount=0;
公共静态void main(字符串[]args)
{
ArrayList temp=新的ArrayList();
扫描仪输入=新扫描仪(System.in);
System.out.println(“请输入金额:”);
int amount=input.nextInt();
System.out.println(“请输入硬币数量:”);
int numCoins=input.nextInt();
coinValues=新整数[numCoins];
for(int i=0;i当前金额&&(金额>0))
{
对于(int i=0;i0;k--)
{
列表。添加(coinValues[k]);
int currentCoin=list.get(i);
如果(金额>当前金额)
{
金额=金额-当前硬币;
系统输出打印项次(“金额:+金额);
}
tryThis(列表、金额);
}
}
}
}
返回新的ArrayList();
}
公共静态布尔值isValid(ArrayList列表,整数金额)
{
布尔值keepGoing=true;
如果(金额>当前金额)
{
return keepGoing=false;
}
其他的
{
返回继续;
}
}
}
问候,,
Mike

您的基本算法如下所示:

For a given amount
  For each coin type
    Add the coin to a set
    If the set exceeds the amount, discard that set.
    If the set contains more coins than it should, discard the set.
    If the set equals the amount, add that set to the set of valid possibilities.
    Otherwise run the algorithm on each set you've created.
通过回溯,您通常会保留在算法每次迭代中要分配的剩余数量(因此“回溯”,因为您正试图为越来越小的数量找到解决方案)。例如,假设我用一角硬币、五分镍币和一分钱寻找0.07美元:

I start with empty sets.
I add a dime to one set. 
I subtract '10' from my amount.
This is a negative number, so I discard that set: it is invalid.
I add a nickel to another (empty) set.
I subtract '5' from my amount.
This equals 2; so I'll have to keep working on this set. 
Now I'm working with sets that already include one nickel.
I add a dime to one set.
I subtract '10' from my amount.
This is a negative number, so I discard that set: it is invalid.
I repeat this with a nickel; I discard this possibility because (2 - 5) is also negative.
I repeat this with a penny; this is valid but I still have 1 left.
I repeat this whole process again with a starting set of one nickel and one penny, 
  again discarding a dime and nickel, 
  and finally adding a penny to reach an amount of 0: this is a valid set.
Now I go back to empty sets and repeat starting with a nickel, then pennies.
请注意,此算法应产生多个结果:

[nickel, penny, penny]
[penny, nickel, penny]
[penny, penny, nickel]
[penny, penny, penny, penny, penny, penny, penny]
函数式语言自然适合这种递归工作,但您可以在任何语言中复制这种算法

这是一个实现代码的示例,不包括对重复项的优雅修剪:

import java.util.*;

public class Backtrack {

  private static List<List<Integer>> findSets(int amount, List<Integer> coinTypes, int numberOfCoins) {
    List<List<Integer>> results = new ArrayList<List<Integer>>();

    for (Integer coin : coinTypes) {
      List<Integer> result = new ArrayList<Integer>();
      result.add(coin);
      int currentAmount = amount - coin;
      if (currentAmount >=0) { //only continue if we haven't overshot
        if (currentAmount == 0) {
          results.add(result);//this is a valid solution, add it to result set
        } else {//still some value to make up
          if ((numberOfCoins - 1) > 0){//otherwise we shouldn't recurse
            List<List<Integer>> recurseResults = findSets(currentAmount, coinTypes, (numberOfCoins - 1));
            for (List<Integer> recurseResult : recurseResults) {//Have to add this layer's coin in to each result
              recurseResult.add(coin);
            }
            results.addAll(recurseResults);
          }
        }
      }
    }

    return results;
  }

  public static void main(String[] args) {
    // TODO Auto-generated method stub
    int amount = 7;
    List<Integer> coinTypes = new ArrayList<Integer>();
    coinTypes.add(Integer.valueOf(1));
    coinTypes.add(Integer.valueOf(5));
    coinTypes.add(Integer.valueOf(10));
    int numberOfCoins = 3;

    List<List<Integer>> results = findSets(amount, coinTypes, numberOfCoins);
    System.out.println("Number of results: " + results.size());
    for (List<Integer> result : results) {
      System.out.print("Result: ");
      for (Integer coin: result) {
        System.out.println(result.toString() + ",");
      }
    }
  }
}
import java.util.*;
公共类回溯{
私有静态列表查找集(整数金额、列表硬币类型、整数硬币数){
列表结果=新建ArrayList();
用于(整型硬币:硬币类型){
列表结果=新建ArrayList();
结果:添加(硬币);
int currentAmount=金额-硬币;
如果(currentAmount>=0){//仅当我们没有超过
如果(currentAmount==0){
results.add(result);//这是一个有效的解决方案,请将其添加到结果集中
}否则{//还有一些价值需要弥补
如果((numberOfCoins-1)>0){//否则我们不应该递归
List recurseResults=findSets(当前金额,硬币类型,(numberOfCoins-1));
对于(List recurseResult:recurseResults){//必须将此层的硬币添加到每个结果中
递归结果添加(硬币);
}
结果:addAll(递归结果);
}
}
}
}
返回结果;
}
公共静态void main(字符串[]args){
//TODO自动生成的方法存根
整数金额=7;
List coinTypes=new ArrayList();
coinTypes.add(Integer.valueOf(1));
coinTypes.add(Integer.valueOf(5));
coinTypes.add(Integer.valueOf(10));
int numberOfCoins=3;
列表结果=查找集(金额、硬币类型、硬币数量);
System.out.println(“结果数:+results.size());
对于(列表结果:结果){
系统输出打印(“结果:”);
for(整数硬币:结果){
System.out.println(result.toString()+“,”);
}
}
}
}

请进行一些研究,并将问题缩小到特定的问题。您必须使用回溯,还是可以使用贪婪算法?该项目由3部分组成(回溯、贪婪和动态),其中我基本上需要解决相同的问题。您在哪里查找回溯信息?你向老师求助了吗?你读过老师让你读的材料了吗?我在网上和书上都看了。在我的书中,它给出了一个8皇后的例子,并说“回溯方法递增地搜索候选解决方案,一旦确定候选方案不可能是解决方案,就放弃该选项,然后寻找新的候选方案。”这就是我试图找出如何从问题开始的地方。我觉得这是一个明智的算法。经过修改,因此算法可以在不修改的情况下自行运行。+1因为这是可行的,但在回溯中,典型的做法是对候选对象进行排序,并从最大到最小应用它们,以获得不同的组合,避免上面看到的排列。(即[5,1x2]和[1x7])我花了一个半小时才开始做贪婪算法。我