Advertisement
teleias

Java : Changemaking

May 11th, 2014
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 10.71 KB | None | 0 0
  1. import java.util.*;
  2. import java.util.Map.Entry;
  3. import java.io.*;
  4. public class ChangeMaking {
  5.     static int[] denoms = new int[] {10, 7, 6, 1};
  6.     public static void main(String[] args)
  7.     {
  8.         getDenoms();
  9.         int change = getTotalChange();
  10.         info greedy = getGreedyHeuristic(change);
  11.         start(change, greedy);
  12.     }
  13.     public static void getDenoms()
  14.     {
  15.         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  16.         System.out.println("What denominations would you like to use?");
  17.         System.out.println(" *note: answer in this format (any order is okay)");
  18.         System.out.println("  1, 6, 7, 10");
  19.         List<Integer> denomsL = new ArrayList<Integer>();
  20.         denomsL.clear();
  21.         try {
  22.             String input = br.readLine();
  23.             String delim = ",";
  24.             if(!input.contains(","))
  25.             {
  26.                 delim = " ";
  27.             }
  28.             for(String s : input.split(delim))
  29.             {
  30.                 s = s.trim();
  31.                 denomsL.add(Integer.parseInt(s));
  32.             }
  33.             java.util.Collections.sort(denomsL);
  34.             java.util.Collections.reverse(denomsL);
  35.             denoms = new int[denomsL.size()];
  36.             String out = " Using denominations: {";
  37.             for(int i = 0; i < denomsL.size(); i++)
  38.             {
  39.                 int in = denomsL.get(i);
  40.                 denoms[i] = in;
  41.                 out += in + ", ";
  42.                 if(in <= 0)
  43.                 {
  44.                     throw new NumberFormatException();
  45.                 }
  46.             }
  47.             out = out.substring(0, out.length()-2)+"}";
  48.             System.out.println(out);
  49.         } catch (IOException e) {
  50.             e.printStackTrace();
  51.         } catch (NumberFormatException nfe) {
  52.             System.out.println("Invalid entry. Using default values instead.\n {1, 6, 7, 10}");
  53.         }
  54.     }
  55.     public static int getTotalChange()
  56.     {
  57.         int totalChange = 0;
  58.         System.out.println("How much change do we begin with?");
  59.         try {
  60.             Scanner in = new Scanner(System.in);
  61.             totalChange = in.nextInt();
  62.             if(totalChange <= 0)
  63.             {
  64.                 throw new NumberFormatException();
  65.             }
  66.         } catch (NumberFormatException nfe) {
  67.             System.out.println("Invalid entry. Using default values instead.\n {49}");
  68.             totalChange = 49;
  69.         } catch (InputMismatchException ime) {
  70.             System.out.println("Invalid entry. Using default values instead.\n {49}");
  71.             totalChange = 49;
  72.         }
  73.         return totalChange;
  74.     }
  75.     public static info getGreedyHeuristic(int change)
  76.     {
  77.         info greedy = new info();
  78.         int leftover = 0;
  79.         int coinsUsed = 0;
  80.         for(int i = 0; i < denoms.length; i++)
  81.         {
  82.             int coinsUsedThisIteration = 0;
  83.             coinsUsedThisIteration = change/denoms[i];
  84.             greedy.uses(coinsUsedThisIteration, denoms[i]);
  85.             coinsUsed += coinsUsedThisIteration;
  86.             leftover = change = change%denoms[i];
  87.         }
  88.         System.out.println("=======================================================");
  89.         System.out.println("We use attempt to use the Greedy Method as a heuristic.");
  90.         if(leftover != 0)
  91.         {
  92.             System.out.println(" Greedy Method fails to return valid answer.");
  93.             greedy.clear();
  94.             greedy = null;
  95.         }
  96.         else
  97.         {
  98.             System.out.println(" Greedy Method uses a total of "+greedy.size+" coins:");
  99.             greedy.show();
  100.         }
  101.         System.out.println("=======================================================");
  102.         System.out.println();
  103.         return greedy;
  104.     }
  105.     public static void start(int change, info greedy) throws IllegalArgumentException
  106.     {
  107.         try
  108.         {
  109.             if(change <= 0)
  110.             {
  111.                 throw new IllegalArgumentException("Your input ["+change +"] is not an integer greater than 0.\n Please try again with a valid argument.");
  112.             }
  113.             getChange(denoms, change, greedy);
  114.         }
  115.         catch(IllegalArgumentException iae)
  116.         {
  117.             System.out.println(iae.getMessage());
  118.         }
  119.     }
  120.     public static int getChange(int[] d, int c, info greedy)
  121.     {
  122.         info[][] infoArr = new info[denoms.length][];
  123.         for(int i = d.length-1; i >= 0; i--)
  124.         {
  125.             infoArr[i] = new info[c];
  126.             for(int j = 1; j <= c; j++)
  127.             {
  128.                 info currentBest = null;
  129.                 int val = 1; //the amount of coins we're using with the current method.
  130.                 infoArr[i][j-1] = new ChangeMaking.info(greedy);
  131.                 if(d[i] > j)
  132.                 {
  133.                     System.out.println("Current Denom {"+d[i]+" c} is higher than the value of "+j+".");
  134.                     if(i+1 < denoms.length)
  135.                     {
  136.                         if(infoArr[i+1][j-1].size != Integer.MAX_VALUE)
  137.                             infoArr[i][j-1].uses(infoArr[i+1][j-1].coins);
  138.                         else
  139.                             infoArr[i][j-1].size = Integer.MAX_VALUE;
  140.                         System.out.println(" Use previous denom's coins ("+(infoArr[i+1][j-1].size==Integer.MAX_VALUE?"n/a":infoArr[i+1][j-1].size)+").");
  141.                     }
  142.                     else
  143.                     {
  144.                         infoArr[i][j-1].size = Integer.MAX_VALUE;
  145.                     }
  146.                     System.out.println();
  147.                     continue;
  148.                 }
  149.                 int leftover = j-d[i];
  150.                 boolean isValid = infoArr[i][j-1].uses(1, d[i]);
  151.                
  152.                 System.out.println("To make "+j+"c when highest denom {"+d[i]+" c}.");
  153.                 print("Use 1x  "+d[i]+"c coins to make "+(d[i])+" cents. Leaves "+leftover+"c left over.\n");
  154.                
  155.                 //We just used the highest denomination as much as possible.
  156.                 // Is there anything left over (are we done)?
  157.                 if(leftover > 0)
  158.                 {
  159.                     //I guess there is some left over.
  160.                    
  161.                     if(infoArr[i][leftover-1] != null && !infoArr[i][leftover-1].isEmpty() && infoArr[i][leftover-1].isValid())
  162.                     {
  163.                         print("Use leftovers from this row.\n");
  164.                         infoArr[i][j-1].uses(infoArr[i][leftover-1].coins);
  165.                     }
  166.                     //if we're working with the smallest denomination,
  167.                     // we're unable to look up the chart for previous answers.
  168.                     else if(i+1 == denoms.length)
  169.                     {
  170.                         //Hence, we're unable to make change.
  171.                         print(" We cannot make change with coins up to this denomination. ([Not Optimal]/[No] Previous Answer).\n\n");
  172.                         infoArr[i][j-1].size = Integer.MAX_VALUE;
  173.                         continue;
  174.                     }
  175.                     //if the previous denom's answer is blank,
  176.                     // we can assume that it isn't correct.
  177.                     else if(infoArr[i+1][leftover-1] == null || infoArr[i+1][leftover-1].isEmpty() || !infoArr[i+1][leftover-1].isValid())
  178.                     {
  179.                         print(" We cannot make change with coins up to this denomination.\n");
  180.                         print("  We try using the last denom's info:\n");
  181.                         //we now backtrack, throwing out current algorithm out the window.
  182.                         // therefore, try to use the previous denom's answer.
  183.                         //does it exist?
  184.                         if(!infoArr[i+1][j-1].isEmpty() && infoArr[i+1][j-1].isValid())
  185.                         {
  186.                             //the previous answer had no valid way to make the change. We'll use that.
  187.                             print("   Success!\n");
  188.                             //this arr copies the previous denom's.
  189.                             infoArr[i][j-1] = infoArr[i+1][j-1];
  190.                             infoArr[i][j-1].show();
  191.                             print("\n");
  192.                         }
  193.                         else
  194.                         {
  195.                             //the previous answer had no valid way to make the change.
  196.                             print("   Failure.\n");
  197.                             print(" We cannot make change with coins up to this denomination (optimally?).\n\n");
  198.                             infoArr[i][j-1].size = Integer.MAX_VALUE;
  199.                         }
  200.                         continue;
  201.                     }
  202.                     //if the previous denom's answer is not blank,
  203.                     // and the previous answer exists,
  204.                     // then we combine our greedy answer with the previous leftover answer.
  205.                     else
  206.                     {
  207.                         print(" To get the extras, add "+infoArr[i+1][leftover-1].size+" coins.\n");
  208.                         //we'll combine all of the leftover's coins with our current answer.
  209.                         infoArr[i][j-1].uses(infoArr[i+1][leftover-1].coins);                      
  210.                     }
  211.                 }
  212.                 //if the previous answer is valid AND
  213.                 // the previous answer's size is smaller than our current+leftover answer AND
  214.                 // the previous answer was legitimate (non-zero).
  215.                 if(i+1 < denoms.length &&
  216.                         infoArr[i][j-1].size > infoArr[i+1][j-1].size &&
  217.                         infoArr[i+1][j-1].isValid())
  218.                 {
  219.                     //then we use the smaller answer (the previous overwrites the current).
  220.                     infoArr[i][j-1] = infoArr[i+1][j-1];
  221.                     print(" However, this method is worse than the previous one,\n  so we're going to not use this denom.\n");
  222.                 }
  223.                 if(!infoArr[i][j-1].isValid())
  224.                 {
  225.                     print(" We cannot make change with coins up to this denomination (optimally?).\n\n");
  226.                     continue;
  227.                 }
  228.                 print(" We use "+infoArr[i][j-1].size+" coins in total.\n");
  229.                 infoArr[i][j-1].show();
  230.                 System.out.println();
  231.                
  232.                 if(currentBest == null || currentBest.size > infoArr[i][j-1].size)
  233.                 {
  234.                     currentBest = infoArr[i][j-1];
  235.                 }
  236.                 infoArr[i][j-1] = currentBest;
  237.             }
  238.             print("\n\n");
  239.         }
  240.         if(infoArr[0][c-1].isValid() && !infoArr[0][c-1].isEmpty())
  241.         {
  242.             System.out.println("========================================================");
  243.             System.out.println("It takes "+infoArr[0][c-1].size+" coin"+(infoArr[0][c-1].size>1?"s":"")+" to make "+c+"c.");
  244.             System.out.println("========================================================");
  245.         }
  246.         else
  247.         {
  248.             System.out.println("==================================================================================");
  249.             System.out.println("We cannot make change with coins up to these denominations and change amount of "+c+".");
  250.             System.out.println("==================================================================================");
  251.         }
  252.         return infoArr[0][c-1].size;
  253.     }
  254.     static boolean debug = true;
  255.     public static void print(String str)
  256.     {
  257.         if(debug)
  258.         {
  259.             System.out.print(str);
  260.         }
  261.     }
  262.     public static class info
  263.     {
  264.         public info(){};
  265.         public info(info _greedy){ greedy = _greedy;};
  266.         info greedy;
  267.         HashMap<Integer, Integer> coins = new HashMap<Integer, Integer>();
  268.         int size = 0;
  269.        
  270.         //Adds information to hashmap.
  271.         // {n: number
  272.         // {c: coins
  273.         //  10x 5c coins would be n=10, c=5
  274.         public boolean uses(int n, int c)
  275.         {
  276.             if(n != 0)
  277.             {
  278.                 int previous = 0;
  279.                 if(coins.get(c) != null)
  280.                 {
  281.                     previous = coins.get(c);
  282.                 }
  283.                 coins.put(c, n+previous);
  284.                 updateSize();
  285.             }
  286.             return isValid();
  287.         }
  288.         //Copies parameter's hashmap.
  289.         public boolean uses(HashMap<Integer, Integer> hm)
  290.         {
  291.             for(Entry<Integer, Integer> e : hm.entrySet())
  292.             {
  293.                 int previous = 0;
  294.                 if(coins.get(e.getKey()) != null)
  295.                 {
  296.                     previous = coins.get(e.getKey());
  297.                 }
  298.                 coins.put(e.getKey(), e.getValue()+previous);
  299.             }
  300.             updateSize();
  301.             return isValid();
  302.         }
  303.         public void updateSize()
  304.         {
  305.             size = 0;
  306.             for(Entry<Integer, Integer> entry : coins.entrySet())
  307.             {
  308.                 size += entry.getValue();
  309.             }
  310.             if(greedy != null && greedy.size < size)
  311.             {
  312.                 //If at this point, the greedy algorithm is better, then we disregard this iteration entirely
  313.                 // as it will _never_ lead to an optimal answer.
  314.                 clear();
  315.                 size = Integer.MAX_VALUE;
  316.             }
  317.         }
  318.         public void show()
  319.         {
  320.             for(Entry<Integer, Integer> entry : coins.entrySet()) {
  321.                 Integer key = entry.getKey();
  322.                 Integer value = entry.getValue();
  323.                 if(entry.getValue() != 0)
  324.                     System.out.println("  "+String.format("%3s", key)+"c ("+String.format("%3s", "x"+value)+")");
  325.             }
  326.         }
  327.         public boolean isValid()
  328.         {
  329.             return size != Integer.MAX_VALUE;
  330.         }
  331.         public boolean isEmpty()
  332.         {
  333.             return size == 0;
  334.         }
  335.         public void clear()
  336.         {
  337.             coins.clear();
  338.             updateSize();
  339.         }
  340.     }
  341. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement