算法设计与分析: 4-11 硬币找钱问题

4-11 硬币找钱问题


问题描述

设有 6 种不同面值的硬币,各硬币的面值分别为 5 分,1 角,2 角,5 角,1 元,2 元。 现要用这些面值的硬币来购物和找钱。购物时可以使用的各种面值的硬币个数存于数组 Coins[1:6]中,商店里各面值的硬币有足够多。在 1 次购物中希望使用最少硬币个数。
例如,1 次购物需要付款 0.55 元,没有 5 角的硬币,只好用 2*20+10+5 共 4 枚硬币来 付款。如果付出 1 元,找回 4 角 5 分,同样需要 4 枚硬币。但是如果付出 1.05 元(1 枚 1 元和 1 枚 5 分),找回 5 角,只需要 3 枚硬币。这个方案用的硬币个数最少。

对于给定的各种面值的硬币个数和付款金额,编程计算使用硬币个数最少的交易方案。

数据输入:
每一行有 6 个整数和 1 个有 2 位小数的实数。分别表示可以使用的各种面值的硬币个数和付款金额。


Java

import java.util.Scanner;

public class YingBiZhaoQian {

    private static int[] coins = new int[6];
    private static int[] c = {5, 10, 20, 50, 100, 200};
    private static int count = 0;
    private static int cost;


    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        while (true) {

            count = 0;
            for (int i = 0; i < 6; i++) {
                coins[i] = input.nextInt();
            }

            double costt;
            costt = input.nextDouble();
            cost = (int) (costt * 100);

            getMinCount();
        }
    }

    private static void getMinCount() {
        for (int i = 5; i >= 0; i--) {  //先找面值较大的硬币
            if (coins[i] > 0) {  //如果硬币数量不为0,则可以用此面值硬币
                int[] cc = new int[i + 1];
                cc[0] = 0;
                for (int k = 1; k <= i; k++) {
                    cc[k] = c[k - 1]; //相当于将c[0,i-1]复制到cc[1,i]
                }
                for (int j = 0; j <= i; j++) {
                    if (cost >= (c[i] - cc[j])) {  //如果要找的钱数>=(当前硬币面值-(比当前硬币面值小的硬币||0)),即当前硬币面值可用
                        //比如要找0.55元,2元数量为0,不可用,考察1元,1元-5角=5角<0.55元,1元可用
                        if (coins[i] >= cost / (c[i] - cc[j])) { //如果已有硬币的数量>=?
                            count += cost / (c[i] - cc[j]) + 1;  //总的要找的钱数+=?+1

                            if (contains(c[i] - cc[j]) != -1) { //如果当前硬币面值-比它小的某一硬币面值恰好等于另外某一硬币面值
                                count--;  //要找的总硬币数-1
                                coins[contains(c[i] - cc[j])] -= cost / (c[i] - cc[j]); //另外某一硬币数量 -= ?
                                System.out.print(" " + cc[j]);
                            } else {  //如果当前硬币面值-比它小的某一硬币面值不等于另外某一硬币面值
                                System.out.print(" " + c[i]);
                                System.out.print(" " + cc[j]);
                                coins[i] -= cost / (c[i] - cc[j]);
                            }
                            cost = cost % (c[i] - cc[j]);    //剩余要找的钱数
                            if (contains(c[i]) == -1)
                                break;
                        } else {  //如果已有硬币的数量<?
                            System.out.print(" " + c[i]);
                            count += coins[i];  //总的要找的钱数 += 当前硬币的数量
                            cost = cost - c[i] * coins[i];  //要找的钱数-已找的钱数
                            coins[i] = 0;   //当前硬币数量用光
                        }
                    }
                }
                //剩下的钱不够支付了
                if (!checkLast(i, cost)) {
                    //检查是否可以用当前的币值来支付
                    int hasLest = cost / c[i] + 1;
                    if (hasLest <= coins[i]) {
                        count += hasLest;
                        count += getBackMin(c[i] * hasLest - cost);
                        cost = 0;
                        break;
                    } else
                        break;
                }
            }

        }

        if (count == 0 || cost != 0) {
            System.out.println("impossible");
        } else {
            System.out.println();
            System.out.println("Coins: " + count);
            System.out.println("-----------");
        }
    }

    private static int contains(int a) {
        for (int i = 0; i < 6; i++) {
            if (c[i] == a && coins[i] > 0)
                return i;
        }

        return -1;
    }

    private static int getBackMin(int k) {
        int count = 0;
        for (int i = 5; i >= 0; --i) {
            count += k / c[i];
            k = k % c[i];
        }

        return count;
    }

    private static boolean checkLast(int index, int co) {
        int sum = 0;
        for (int i = index - 1; i >= 0; --i) {
            sum += c[i] * coins[i];
        }
        if (co <= sum)
            return true;
        else
            return false;
    }
}

Input & Output

2 4 2 2 1 0 0.95
 100 5
Coins: 2
-----------
2 4 2 0 1 0 0.55
 100 50 5
Coins: 3
-----------

Reference

王晓东《计算机算法设计与分析》(第3版)P132
https://blog.csdn.net/u012319493/article/details/50000539

猜你喜欢

转载自blog.csdn.net/ioio_/article/details/81066594