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