简体   繁体   English

提供有限数量钞票的ATM算法

[英]ATM algorithm of giving money with limited amount of bank notes

All the change-making problem in the web talk only about ideal situation where we have unlimited ammount of coins/banknotes of every kind. 网上所有的变革问题都只谈到了我们拥有无限量的各种硬币/纸币的理想情况。

I want to deal with situation when ATM has limited ammount of: 10,20,50,100,200 bank notes and it has to find way to make change. 我想处理ATM的数量有限的情况:10,20,50,100,200张钞票,它必须找到改变的方法。

I've done sth like that but I cannot deal with for example demand of 110 dollars. 我已经做过那样但我不能处理110美元的需求。 Whole algorithm is in method withdrawCash() you can copy the code it compiles and works. 整个算法在方法withdrawCash() 你可以复制它编译和工作的代码。

Output or 110$: 输出或110 $:

10 * 1 = 10
20 * 4 = 80
Notes of 10 left are 0
Notes of 20 left are 0
Notes of 50 left are 2
Notes of 100 left are 2
Notes of 200 left are 10

public class ATM {
    /** The Constant Currency Denominations. */
    protected static final int[] currDenom = { 10, 20, 50, 100, 200 };

    /** The Number of Currencies of each type */
    protected static int[] currNo = { 1, 4, 2, 2, 10 };
    /** The count. */
    protected int[] count = { 0, 0, 0, 0, 0 };
    protected static int totalCorpus;
    static {
        calcTotalCorpus();
    }

    public static void calcTotalCorpus() {
        for (int i = 0; i < currDenom.length; i++) {
            totalCorpus = totalCorpus + currDenom[i] * currNo[i];
        }
    }

    public ATM() {

    }

    public synchronized void withdrawCash(int amount) {
        if (amount <= totalCorpus) {
            for (int i = 0; i < currDenom.length; i++) {
                if (currDenom[i] <= amount) {//If the amount is less than the currDenom[i] then that particular denomination cannot be dispensed
                    int noteCount = amount / currDenom[i];
                    if (currNo[i] > 0) {//To check whether the ATM Vault is left with the currency denomination under iteration
                        //If the Note Count is greater than the number of notes in ATM vault for that particular denomination then utilize all of them 
                        count[i] = noteCount >= currNo[i] ? currNo[i] : noteCount;
                        currNo[i] = noteCount >= currNo[i] ? 0 : currNo[i] - noteCount;
                        //Deduct the total corpus left in the ATM Vault with the cash being dispensed in this iteration
                        totalCorpus = totalCorpus - (count[i] * currDenom[i]);
                        //Calculate the amount that need to be addressed in the next iterations
                        amount = amount - (count[i] * currDenom[i]);
                    }
                }
            }
            displayNotes();
            displayLeftNotes();

        } else {
            System.out.println("Unable to dispense cash at this moment for this big amount");
        }

    }

    private void displayNotes() {
        for (int i = 0; i < count.length; i++) {
            if (count[i] != 0) {
                System.out.println(currDenom[i] + " * " + count[i] + " = " + (currDenom[i] * count[i]));
            }
        }
    }

    private void displayLeftNotes() {
        for (int i = 0; i < currDenom.length; i++) {
            System.out.println("Notes of " + currDenom[i] + " left are " + currNo[i]);
        }

    }

    public static void main(String[] args) {
        new ATM().withdrawCash(110);
    }
}

It can be done relatively easily, you just have to keep trying adding bank notes that left in every possibility and then discard possibilities, which already have more than you try to achieve. 它可以相对容易地完成,你只需要继续尝试添加留在各种可能性中的钞票,然后丢弃可能性,这已经超过了你想要达到的程度。

This is working code, values are "bank notes" values and in "ammounts" are ammounts of bank notes you have : 这是工作代码,值是“银行票据”值,而“ammounts”是您拥有的银行票据的代码:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class JavaApplication55 {
    int[] values = {10,20,50,100,200};

    public static void main(String[] args) {
        int[] values = {10,20,50,100,200};
        int[] ammounts = {10,10,10,10,10};
        List<Integer[]> results = solutions(values, ammounts, new int[5], 180, 0);
        for (Integer[] result : results){
            System.out.println(Arrays.toString(result));
        }

    }

    public static List<Integer[]> solutions(int[] values, int[] ammounts, int[] variation, int price, int position){
        List<Integer[]> list = new ArrayList<>();
        int value = compute(values, variation);
        if (value < price){
            for (int i = position; i < values.length; i++) {
                if (ammounts[i] > variation[i]){
                    int[] newvariation = variation.clone();
                    newvariation[i]++;
                    List<Integer[]> newList = solutions(values, ammounts, newvariation, price, i);
                    if (newList != null){
                        list.addAll(newList);
                    }
                }
            }
        } else if (value == price) {
            list.add(myCopy(variation));
        }
        return list;
    }    

    public static int compute(int[] values, int[] variation){
        int ret = 0;
        for (int i = 0; i < variation.length; i++) {
            ret += values[i] * variation[i];
        }
        return ret;
    }    

    public static Integer[] myCopy(int[] ar){
        Integer[] ret = new Integer[ar.length];
        for (int i = 0; i < ar.length; i++) {
            ret[i] = ar[i];
        }
        return ret;
    }
}

This code having this ouput (it is output for 10,20,50,100,200 bank notes, you have 10 of each of them and you want to get 180 in sum) 这个代码有这个输出(它输出10,20,50,100,200张钞票,你每个都有10个,你想得到总和180)

[10, 4, 0, 0, 0]
[9, 2, 1, 0, 0]
[8, 5, 0, 0, 0]
[8, 0, 2, 0, 0]
[8, 0, 0, 1, 0]
[7, 3, 1, 0, 0]
[6, 6, 0, 0, 0]
[6, 1, 2, 0, 0]
[6, 1, 0, 1, 0]
[5, 4, 1, 0, 0]
[4, 7, 0, 0, 0]
[4, 2, 2, 0, 0]
[4, 2, 0, 1, 0]
[3, 5, 1, 0, 0]
[3, 0, 3, 0, 0]
[3, 0, 1, 1, 0]
[2, 8, 0, 0, 0]
[2, 3, 2, 0, 0]
[2, 3, 0, 1, 0]
[1, 6, 1, 0, 0]
[1, 1, 3, 0, 0]
[1, 1, 1, 1, 0]
[0, 9, 0, 0, 0]
[0, 4, 2, 0, 0]
[0, 4, 0, 1, 0]

Making amount from given set of coins is np complete problem because it reduces to subset sum problem or knapsack problem. 从给定的硬币组中获得金额是np完全问题,因为它减少到子集和问题或背包问题。 But you have a pseudo polynomial time algorithm for the knapsack problem which is efficient enough for your purpose. 但是你有一个针对背包问题的伪多项式时间算法,它足以满足你的需要。 Here you are using a greedy algorithm which gives solutions which can give solution for most cases but fails for some and hence cannot be used but you can use a combination of the pseudo polynomial time algorithm and the greedy to get an efficient algorithm that solves for all cases with high speed solution for best cases. 在这里,您使用的是贪婪算法,该算法提供的解决方案可以为大多数情况提供解决方案,但对某些情况失败,因此无法使用,但您可以使用伪多项式时间算法和贪婪的组合来获得解决所有问题的有效算法最佳案例的高速解决方案。

Pseudo polynomial time solution using knapsack analogy :- 使用背包类比的伪多项式时间解决方案: -

  1. knapsack capacity :- Amount needed for example 110 背包容量: - 例如110所需的数量
  2. items available:- x1*10,x2*20....xn*100. 可用项目: - x1 * 10,x2 * 20 .... xn * 100。 Cost and weight of items as same. 物品的成本和重量相同。
  3. Solve Knapsack for max profit using DP solution 使用DP解决方案解决背包以获取最大利润
  4. If max profit == knapsack capacity then you have a solution so retrace it using DP matrix. 如果最大利润==背包容量,那么你有一个解决方案,所以使用DP矩阵回溯它。
  5. else there is no way you can get the amount using current available coins. 否则你无法使用当前可用的硬币获得金额。

Time complexity:- O(Amount*Items) 时间复杂度: - O(Amount*Items)

Combination of greedy and DP solution :- 结合贪婪和DP解决方案: -

boolean greedysolve = false, DPsolve = false;

greedysolve = YourSolution();

if(!greedysolve) {

   DPsolve = KnapsackSolution(); 
}

else {

   return(greedy_solution);
}

if(!DPsolve) {

   return(DPsolution);

}

return(null);  // No solution

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM