题目:给定一堆固定面值的硬币,比如2,5,7,求拼成指定数值所花费的最小硬币数,比如给定27,最小硬币数应为5,硬币分别为:5,5,5,5,7。这里只用到了一个7,如果自己枚举,可能会先尽可能的用7,那么硬币为:7,7,7,2,2,2,这里就用到了6枚硬币,不是最小数量。
分析:设ak代表最后一枚硬币面值,则ak只可能是2,5,7,本题的最后一步为当 前k-1枚硬币拼法确定的情况下,加上最后一枚硬币ak的面值即可。
设f(x)=最小用多少枚硬币拼出x,
当ak=7时,f(27)=f(27-7)+1
当ak=5时,f(27)=f(27-5)+1
当ak=2时,f(27)=f(27-2)+1
所以f(27)=min{f(27-2)+1,f(27-5)+1,f(27-7)+1}
初始条件为:f[0]=0,因为硬币的面值最小为2,所以f(1)是拼不出来的,这里设置边界情况:f[i]=Integer.MAX_VALUE,当拼不出来的时候就为正无穷。
计算顺序就为从小到大,前面的先计算,后面的可以用前面计算的结果。
代码如下:
package com.coin.test;
public class Main {
public static void main(String[] args){
int[] A = {2,5,7};
int M = 27;
System.out.println(coinMin(A,M));
}
public static int coinMin(int[] A,int M){
//A数组存在硬币的种类,M表示能拼成的硬币总和
//0-M总数为M+1,由于用到数字27,而且数组下标从0开始,所以数组的长度就设置为M+1
//A数组长度为n,数组下标从0到n-1即可
int[] f = new int[M+1];
int n = A.length;
//设置初始值条件
f[0]=0;
int i,j;
for(i=1;i<=M;i++){
//这里设置边界条件,拼不出来的话就为无穷大
f[i]=Integer.MAX_VALUE;
for(j=0;j<n;j++){
//这里为边界条件,重要
//拼成的数值要比硬币的面值要大
if(i>=A[j] && f[i-A[j]] != Integer.MAX_VALUE){
//转移方程
f[i] = Math.min(f[i-A[j]]+1, f[i]);
}
}
}
if(f[M]==Integer.MAX_VALUE){
f[M] = -1;
}
return f[M];
}
}
运行结果:
5