Java 打印最小更改算法中使用的面额时出现问题

Java 打印最小更改算法中使用的面额时出现问题,java,dynamic,recursion,dynamic-programming,coin-change,Java,Dynamic,Recursion,Dynamic Programming,Coin Change,所以我写了一个递归算法来解决这个问题,计算出一组特定面额的最小数量的“硬币”可能达到一个给定的总和。这个算法似乎是可行的,但因为它是递归的,并且在选择一个或另一个选项之前会计算所有可能的选项,所以我很难想出一种方法来打印出所使用的面额。因此,基本上我可以计算出可能使用的最少数量的硬币,但不能计算它们是哪种硬币。这是我用来驱动它的代码和主要方法。任何关于简化算法本身的建议都将受到欢迎 public class DynamicCoinChange { public static void

所以我写了一个递归算法来解决这个问题,计算出一组特定面额的最小数量的“硬币”可能达到一个给定的总和。这个算法似乎是可行的,但因为它是递归的,并且在选择一个或另一个选项之前会计算所有可能的选项,所以我很难想出一种方法来打印出所使用的面额。因此,基本上我可以计算出可能使用的最少数量的硬币,但不能计算它们是哪种硬币。这是我用来驱动它的代码和主要方法。任何关于简化算法本身的建议都将受到欢迎

public class DynamicCoinChange {

    public static void main(String[] args) {
        int[] denoms = {1, 6, 10, 25};
        int numCoins = dynamicCoinChange(denoms, 18, 3);
        System.out.println(numCoins);
    }

    public static int dynamicCoinChange(int[] denoms, int amt, int start) {
        if (amt == 0 || start < 0) {
            return 0;
        } else if (amt == 1) {
            return 1;
        } else if (denoms[start] > amt || 
                dynamicCoinChange(denoms, amt, start-1) < 
                (1 + dynamicCoinChange(denoms, amt-denoms[start], start)) &&
                !(dynamicCoinChange(denoms, amt, start-1) == 0)) {
            return dynamicCoinChange(denoms, amt, start-1);
        } else {
            return 1 + dynamicCoinChange(denoms,amt-denoms[start], start);
        }
    }
}
公共类动态更改{
公共静态void main(字符串[]args){
int[]denoms={1,6,10,25};
int numCoins=动态变化(denoms,18,3);
System.out.println(numCoins);
}
公共静态int动态inchange(int[]denoms,int amt,int start){
如果(金额==0 | |开始<0){
返回0;
}否则如果(金额==1){
返回1;
}否则如果(denoms[开始]>金额| |
动态变化(起点、金额、起点-1)
(1+动态增量变化(增量、金额增量[启动]、启动))&&
!(动态增量变化(数据、金额、开始-1)=0){
返回动态更改(denoms、amt、start-1);
}否则{
返回1+dynamiccinchange(denoms,amt denoms[start],start);
}
}
}

最小变化问题不需要递归编程。它可以用一种更简单的迭代方式编程

int[] denoms = { 1, 6, 10, 25 };
int amt = 18;
double[] min = new double[ amt + 1 ];

for( int i = 1; i < min.length; i++ ) { // We're keeping min[ 0 ] as 0/
    min[ i ] = Double.POSITIVE_INFINITY;
}

for( int i = 1; i <= amt; i++ ) {

   for( int j = 0; j <= N - 1; j++ ) {

       if( denoms[ j ] <= i && min[ i - denoms[ j ] ] + 1 < min[ i ] )
           min[ i ] = min[ i - denoms[ j ] ] + 1;

   }
}
int[]denoms={1,6,10,25};
国际金额=18;
double[]最小值=新的double[amt+1];
对于(inti=1;i对于(int i=1;i我们需要知道两条信息:

  • 当选择硬币作为最佳解决方案时
  • 选择哪种硬币作为最佳解决方案
根据您的算法,我们知道无论何时返回
1
,我们都会选择一枚硬币。我们还知道,在所选硬币的索引处选择的硬币是
start
。因此,我们有解决此问题的信息

由于性能在这里不是问题,我们只需传递一个coins参数,该参数在选择coins时填充

public static int dynamicCoinChange(int[] denoms, int amt, int start, ArrayList<Integer> coins) {
    if (amt == 0 || start < 0) {
        return 0;
    } else if (amt == 1) {
        coins.add(1);
        return 1;
    } else if (denoms[start] > amt 
            // Note that these calls are not guaranteed to be in our solution
            // Thus, we make a copy to prevent the calls from modifying our solution
            || dynamicCoinChange(denoms, amt, start-1, new ArrayList<Integer>(coins)) < 
                (1 + dynamicCoinChange(denoms, amt-denoms[start], start, new ArrayList<Integer>(coins))) 
            && !(dynamicCoinChange(denoms, amt, start-1, new ArrayList<Integer>(coins)) == 0)) {
        return dynamicCoinChange(denoms, amt, start-1, coins);
    } else {
        coins.add(denoms[start]);
        return 1 + dynamicCoinChange(denoms,amt-denoms[start], start, coins);
    }
}
public static int dynamiccinchange(int[]denoms,int amt,int start,ArrayList coins){
如果(金额==0 | |开始<0){
返回0;
}否则如果(金额==1){
增加(1);
返回1;
}否则如果(denoms[开始]>金额
//请注意,这些调用不一定在我们的解决方案中
//因此,我们制作一个副本以防止调用修改我们的解决方案
||动态更改(denoms、amt、start-1、新阵列列表(硬币))<
(1+dynamiccinchange(denoms,amt denoms[start],start,new ArrayList(硬币)))
&&!(DynamicInchange(denoms、amt、start-1、新阵列列表(硬币))=0){
返回动态更改(denoms、amt、start-1、硬币);
}否则{
硬币。添加(denoms[开始]);
返回1+dynamiccinchange(denoms,amt denoms[start],start,coins);
}
}
由于这需要我们更改方法签名,我们还必须修改驱动程序:

public static void main(String[] args) {
    int[] denoms = {1, 6, 10, 25};
    ArrayList<Integer> coins = new ArrayList<Integer>();
    int numCoins = dynamicCoinChange(denoms, 7, 3, coins);
    for (Integer coin : coins)
        System.out.println(coin);
    System.out.println(numCoins);
}
publicstaticvoidmain(字符串[]args){
int[]denoms={1,6,10,25};
ArrayList硬币=新的ArrayList();
int numCoins=动态变化(德努姆斯,7,3,硬币);
用于(整数硬币:硬币)
系统输出打印(硬币);
System.out.println(numCoins);
}

在递归调用结束时,
coins
应该包含按时间顺序选择的硬币列表。

我知道这是低效的,但我有点想递归地这样做,因为我喜欢递归哈哈。:/No,这不起作用,因为我们基本上在计算很多可能的解决方案,然后根据co选择一个比较。是的,我知道这是低效的哈哈。如果你去掉倒数第二个条件的后半部分,
| | dynamiccinchange(denoms,amt,start-1)<(1+dynamiccinchange(denoms,amt denoms[start],start))&!(dynamiccinchange(denoms,amt,start-1)==0)
这应该还可以。你是说从“| |”开始删除还是从“&&”开始删除?我不确定这一点。因为这样一来,你就不能保证面额小于最大面额是正确的第一选择,即使如此!(denom[start]>amt)你是对的。这组硬币不允许我使用贪婪选择属性。我将我的解决方案修改为伪尾部调用方法。如果不是更糟的话,它应该和你当前的解决方案一样低效。