给定不同面额的硬币coins和一个总金额amount。计算并输出可以凑成总金额所需的最少的硬币个数和使用的硬币。
网上介绍动态规划的文章已经很多了, 我的这篇文章分析了我自己分析硬币问题的算法在二维数组的效能分析,其中用了Intellij IDEA的工具。
代码
public class DynamicProgramming {
public static void main(String[] args) {
int[] coins = {2,5};
int capacity = 21;
CoinValue CV = new CoinValue();
CV.Coinvalue(coins,capacity);
}
}
//币值问题
class CoinValue {
public void Coinvalue(int[] coins, int capacity) {
//规划数组
int[][] map = new int[coins.length + 1][capacity + 1];
//初始化 第一行列为0
for (int i = 0; i < coins.length + 1; i++) {
map[i][0] = 0;
}
for (int i = 0; i < capacity + 1; i++) {
map[0][i] = 0;
}
//填数组,
/*
* 容量小于当前币 填写上一种币的当前容量的位置存储值
* 容量等于当前币 填写1
* 容量大于当前币
* */
for (int i = 1; i < coins.length + 1; i++) {
for (int j = 1; j < capacity + 1; j++) {
if (coins[i - 1] == j) {
map[i][j] = 1;
} else if (coins[i - 1] > j) {
map[i][j] = map[i - 1][j];
}
//容量大于当前币
else {
//判断减去该币面额后的容量在该币的位置的值是否为0
if (map[i][j - coins[i - 1]] == 0) {
//判断减去该币面额后的容量在该币的位置的上一位置的值是否为0,
if (map[i - 1][j - coins[i - 1]] == 0) {
map[i][j] = 0;
//不为0则当前值填写减去该币面额后的容量在该币的位置的上一位置的值
} else {
map[i][j] = map[i - 1][j - coins[i - 1]] + 1;
}
}//减去该币面额后的容量在该币的位置的值 + 1
else {
map[i][j] = 1 + map[i][j - coins[i - 1]];
}
}
}
}
//得到需要最少硬币数,及其在数组的横坐标
int x = 0;
for (int i = coins.length; i > 0; i--) {
if (map[i][capacity] != 0) {
System.out.println("min :" + map[i][capacity]);
x = i;
break;
}
}
//判断是否无解
if (x == 0) {
System.out.println("no permutation");
}
/* 查看x以及map
System.out.println(x);
for (int i = 0; i < coins.length + 1; i++) {
for (int j = 0; j < capacity + 1; j++) {
System.out.print(map[i][j] + " ");
}
System.out.println("");
}
*/
//存储使用硬币数时使用的硬币
ArrayList<Integer> coin = new ArrayList<>();
//从最少数位置往回找使用过的硬币(一定有解)
//存储x更新至最小面额硬币前的当前币种
int temp = 0;
//容量 <= 0时停止循环
while (capacity > 0 && x > 0) {
//容量小于x,说明当币面额,此时是继承上一币种的值,减小直至合理
while (capacity < coins[x - 1]) {
x--;
//说明前一次capacity尽管大于当前币种面值,但是减去该面值后,剩余capacity小于最小面值
if (x <= 0) {
//将x回到更新至最小面额硬币前的当前币种的下一币种
x = temp - 1;
//将capacity回退到更新至最小面额硬币前的当前币种时的capacity
capacity = capacity + coins[temp - 1];
//将最优解末尾回退
coin.remove(coin.size() - 1);
break;
}
}
temp = x;
//更新容量,此时容量只能大于等于币的面额
capacity = capacity - coins[x - 1];
coin.add(coins[x - 1]);
}
//输出硬币
for (int i = 0; i < coin.size(); i++) {
System.out.print(coin.get(i) + " ");
}
}
}