面值为2,5,7的三种硬币,数量无限,凑出27元最少需要多少枚硬币?
本题可以用DP或者DFS的方法求解,这里展示DP的四步求解过程:
1.确定状态
易得,a1+a2+a3+..+ak = 27 在最后一步中,当前面值加上第ak枚硬币得出27 (ak = 2,5,7)
则倒数第二步为:a1+a2+a3+..+ak-1 = (27-ak),实为本题的子问题
2.状态转移方程
设 f(x) = 凑出x元需要的最少硬币
那么,f(x) = min(f(x-2)+1,f(x-5)+1,f(x-7)+1)
即f(x)等于前一步中得到的面值所需的硬币数加上最后的这1枚硬币
min表示 在f(x-2),f(x-5),f(x-7)中选择使用硬币最少的加上最后一 枚
3.初始化条件和边界
f(0) = 0
令无法凑出的面值需要-1个硬币,并用-1代表正无穷
f(x<0) = -1
f(1) = -1
f(3) = -1
....
4.确定计算顺序
f(x) = min(f(x-2)+1,f(x-5)+1,f(x-7)+1)
因需要从已经得出的结果中求f(x)
所以要从小往大遍历计算
5.代码
package dp;
public class coinsExchange {
public static void main(String[] args) {
int[] f = new int[28];
f[0] = 0;
for (int i = 1; i < f.length; i++) {
int x = i - 2 < 0 ? -1 : add(f[i - 2], 1);
int y = i - 5 < 0 ? -1 : add(f[i - 5], 1);
int z = i - 7 < 0 ? -1 : add(f[i - 7], 1);
f[i] = min(x, y, z);
}
System.out.println(f[27]);//5
}
//-1 代表正无穷,正无穷+任何数等于正无穷
private static int add(int x, int y) {
if(x == -1)
return -1;
return x + y;
}
private static int min(int x, int y, int z) {
int t = min(x,y);
return min(t,z);
}
//-1 代表正无穷,正无穷小于其它数
private static int min(int x, int y) {
if(x == -1 && y == -1)
return x;
if(x == -1)
return y;
if(y == -1)
return x;
return Math.min(x,y);
}
}