第一天先看些简单的例子:参考书籍:算法设计与分析基础第三版
例1 《币值最大化问题》
题目:给定一排n个硬币,其面值均为正整数c1,c2,...,cn,这些整数并不一定两两不同。请问如何选择硬币,使得在其原始位置互不相邻的条件下,所选硬币的总金额最大。
分析:
1.最大金额用F(n)表示,然后找到F(n)的递推关系,我们可以分成两组:一组是包含最后一个硬币的,另一组是不包含最后一个硬币的。
2.那第一组:F(n) = cn+F(n-2);
第二组:F(n) = F(n-1);
即 F(n)=max{cn+F(n-2),F(n-1)},n>1
3.再结合初始条件:F(0)=0(下标从1开始)0,F(1)=c1
代码:
public class demo_1 {
static int[] c = new int[10];
static int[] f = new int[10];
static Scanner in = new Scanner(System.in);
public static void main(String[] args) {
int n = in.nextInt();
for (int i = 1; i <= n; i++) {
c[i] = in.nextInt();
}
System.out.println(coinRow(n));
}
private static int coinRow(int n) {
f[0] = 0;
f[1] = c[1];
for (int i = 2; i <= n; i++) {
f[i] = Math.max(c[i] + f[i-2], f[i-1]);
}
return f[n];
}
}
测试数据:
我们假设一排硬币是 5,1,2,10,6,2 。最大金额为17
例2 《找零问题》
题目:需找零金额为n,最少要用多少面值为d1<d2<…<dm的硬币?(m种面值的各种硬币,d1=1,数量无限)
分析:
1.设F(n)是在总金额为n的条件下,使用最少硬币的数量
2.易知F(0) = 0,F(1) = 1;
3.得到n的途径为 n-dj,然后加上一个面值为dj的硬币,因此 F(n) = min{F(n-dj)} + 1
代码:
public class demo_1 {
static int[] c = new int[10];
static int[] f = new int[10];
static int sum; //总金额
static Scanner in = new Scanner(System.in);
public static void main(String[] args) {
sum = in.nextInt();
int n = in.nextInt(); //硬币种类
c[1] = 1;
for (int i = 2; i <= n; i++) {
c[i] = in.nextInt();
}
System.out.println(changeMaking(n));
}
private static int changeMaking(int n) {
for (int i = 1; i <= sum; i++) {
int temp = 99999999;
int j = 1;
while (j <= n && i >= c[j]) {
temp = Math.min(f[i-c[j]], temp);
j++;
}
f[i] = temp +1;
}
return f[sum];
}
}
测试:sum = 6, n=3,币值分别为1,3,4 F6)= 2
例3《硬币收集问题》下篇介绍