нужна помощь в исправлении этого кода при динамическом программировании/рекурсии при вычислении минимальных монет с использованием Java

У меня есть мой код, который предназначен для возврата минимальной конфигурации монет для внесения сдачи на заданную сумму. Он принимает два параметра, сумму и список номиналов. У меня нет ошибки компиляции, и программа работает, чтобы выдавать результат, но не совсем то, что я получаю. Любая помощь в этом очень ценится.

//this program calculates the minimum coins and distribution of
//denominations required to make change for a given sum
import java.util.*;
import java.io.*;
public class MinCoinCollectionBacktrack {
   private int sum;
   private List<Integer> coins;

   //constructor that takes sum and list of denominations
   //such as [1,5,10,25]
   public MinCoinCollectionBacktrack(int amount,List<Integer> denominationList) {
      sum=amount;
      coins=denominationList;
  }

  //calculate the minimum coins
  //uses map to store sum-->list of combinations
  //eg 3-->[2,1], 4 -->[2,2] for a given denomination list of [1,2,5]
  public  List<Integer> Mincoins() {
   Map<Integer, List<Integer>> lenChoices=new HashMap<Integer,List<Integer>>();
      int maxdenomination=Collections.max(coins);
      Integer sum1= new Integer(sum);
   return minCoins(lenChoices,sum,maxdenomination);

  }

  //wrapper method for MinCoins, it takes a map and updates as when
  //minimum configuration of a sum is found. stores the value
  //as described above
  private List<Integer> minCoins(Map<Integer, List<Integer>> lenChoices, int value,int maxdenomination) {
  //check if sum is a key in map, then return its value
   if (lenChoices.containsKey(value)) {
      return lenChoices.get(value);
  //check if the coinlist contains sum, if yes, it creates a
  //new key value pair to the Map
   } else if (coins.contains(value)) {
      List<Integer> newlist = new ArrayList<Integer>();
      newlist.add(value);
      lenChoices.put(value,newlist);
      return lenChoices.get(value); 
  //if the denomiation is > sum, just return empty list        
   } else if (maxdenomination > value) {
      List<Integer> newlist = new ArrayList<Integer>();
      lenChoices.put(value,newlist);
      return lenChoices.get(value);
  //here is where recursive backtracking happens    
   } else {
      int minLength=0;
      List<Integer> minConfig=new ArrayList<Integer>();
      for (int coin : coins) {
         List<Integer> results = minCoins(lenChoices,value - coin,maxdenomination);
         if (!results.isEmpty()) {
            if (minLength==0 || (1+results.size()) < minConfig.size()) {               
               results.add(coin);
               minConfig=results;
               minLength=minConfig.size();
            }
         }
     }    
     lenChoices.put(value,minConfig);  
     return lenChoices.get(value);
  }
}

public static void main(String[] args) {
   System.out.println("enter the denoninations, hit enter to Zero(0) to finish");
   Scanner console = new Scanner(System.in);
   List<Integer> coinlist= new ArrayList<Integer>();
   int input = console.nextInt();
   while (input>0) {
      coinlist.add(input);
      input = console.nextInt();
   }
   System.out.println("coin collections are :"+ coinlist);
   System.out.println("enter the sum for which you need minimum coins");
   input = console.nextInt();
   MinCoinCollectionBacktrack result=new MinCoinCollectionBacktrack(input,coinlist);
   List<Integer> output = result.Mincoins();
   System.out.println("you require " + output.size() + " coins in the"
                                    + " following combination " + output);

 } 

} 

пожалуйста, не стесняйтесь комментировать потенциальные области улучшения стиля и алгоритма. Спасибо!


person brain storm    schedule 01.08.2013    source источник
comment
Вам действительно нужна карта? Вы проинформированы об уравнении DP для этой проблемы? Вы неправильно реализовали уравнение рекурсии. Попробуйте посмотреть здесь: ccs.neu.edu /home/jaa/CSG713.04F/Информация/Раздаточные материалы/.   -  person    schedule 02.08.2013
comment
//если номинал › сумма, просто верните пустой список Ваш код здесь вернет пустой список для следующего ввода: монеты: {1,2,5,10,20,50,100,500,1000} значение: 150 ваш результат: пустой список; ожидаемый результат: {50 100}   -  person    schedule 02.08.2013
comment
Вот как мой код предназначен для: пустой список используется для поиска на карте. это означает, что никакая комбинация 1000 не может сформировать ожидаемый результат 150, и поэтому я присваиваю его пустому списку, 1000 --> [], где 50 --> [3]. Я тоже могу ошибаться. Пожалуйста, поправьте меня, если вы так думаете.   -  person brain storm    schedule 02.08.2013


Ответы (1)


В общем, ваш код довольно запутанный! Я попробовал несколько изменений, и если я правильно понимаю, что вы пытаетесь сделать, достаточно нескольких новых строк, чтобы получить правильные значения. Конечно, я не пробовал это со всеми возможными комбинациями, поэтому вы можете представить мне ту, которая нарушает результат!

Метод минкойнов:

  public  List<Integer> Mincoins() {
    Map<Integer, List<Integer>> lenChoices=new HashMap<Integer, List<Integer>>();
    Collections.sort(coins, Collections.reverseOrder()); // since later on in the code you are iterating over your coins, it makes sense to sort them with the largest first so that you are slowly left with the bits that can not be divided by the larger values and have more probability to be caught be the small ones
    int maxdenomination=Collections.max(coins);
    Integer sum1= new Integer(sum);
    List<Integer> result = new ArrayList<Integer>();
    for (Integer c: coins) { //as per  Nishant Shreshth's comment, you need to check all invalid coins first and don't bother unless one which produces results is found
      println(c);
      result = minCoins(lenChoices, sum, c, 0);
      lenChoices.clear();
      if (result.size() > 0) break;
    }
    return result;
  }

метод minCoins @ else {

else {
      int minLength=0;
      List<Integer> minConfig=new ArrayList<Integer>();
      for (int coin : coins) {
        List<Integer> results = minCoins(lenChoices, value - coin, maxdenomination);
        if (!results.isEmpty()) {
          if (minLength==0 || (1+results.size()) < minConfig.size()) {               
            results.add(coin);
            minConfig=results;
            minLength=minConfig.size();
          }
          break; // If we already have a result we don't need to look for the rest of the coins!
        }
      }    
      lenChoices.put(value, minConfig);  
      return lenChoices.get(value);
    }
person Petros Koutsolampros    schedule 01.08.2013
comment
кажется, работает, спасибо за ваше время. Я сделаю более энергичный тест. в то время как изменения, которые вы сделали здесь, имеют смысл, я не знаю, почему это необходимо. вы используете break, так как вы начинаете с самого высокого номинала монеты и идете ниже (вы используете список с обратной сортировкой). Я просматривал все номиналы монет и пытался найти наилучшую комбинацию, которую я могу составить, например, сумма 4 может быть составлена ​​из (2,2) и (2,1,1), если мой набор монет равен [1, 2]. Я выберу (2,2), так как его длина мала. Мне трудно найти, где я ошибаюсь, хотя код, кажется, имеет смысл - person brain storm; 02.08.2013