一、贪婪算法
贪婪算法(又叫贪心算法)是指在对问题进行求解时,在每一步的选择中都采取最优的选择,即局部最优,从而希望最后的结果也能达到最优。
贪婪算法得到的结果不一定是最优解(有时候会是最优解),但都相对接近最优解。
二、设计思路:
- 为求解的问题创建数学模型;
- 把求解的问题分成若干个子问题;
- 求解每一个子问题并得到子问题的局部最优解;
- 将所有子问题的局部最优解合成原问题的解。
三、案例
1、区间调度问题
(1)问题描述: 有如下课程及时间,希望尽可能多的将课程安排在一间教室里,如何选择?
(2)思路: 从九点开始,选择结束最早的课为第一节课,得到美术课;选择第一节课结束后开始最早的课,得到数学课;选择第二节课结束后开始最早的课,得到音乐课。图示如下:
该策略的每一步都选择结束最早的课和下一节最早开始的课,每一步都可得到局部最优解,最终得到的结果为美术、数学和音乐,也是这个问题的最优解。
2、背包问题
(1)问题描述: 有一个背包,容量为 35 磅, 现有如下物品。要求装入背包的物品总价值最大,且重量不超出。
(2)思路: 问题要求装入背包的物品总价值最大且重量不超出。那么采取每次先选最贵的装入背包(重量不能超出)的策略。
先选最贵的,音响;下面只能选笔。总价值 = 3000 + 200 = 3200。每一步得到了局部最优解,但这并不是整个问题的最优解。最优解为笔记本 + 吉他,总价值 = 2000 + 1500 = 3500。
3、哈夫曼树
(1)问题描述: 给定一组数
,用这组数构造哈夫曼树的过程如下:
找到
中最小的两个数,设为
、
,将
、
从
中删掉,将他们的和加入到
中,这个过程的费用为
;重复上一步骤,直至
中仅剩一个元素;将所有费用相加,就得到构造哈夫曼树的总费用。
现要求,给定一个数列,求出用该数列构造哈夫曼树的总费用。
(2)思路: 每次选择数组中最小的两个数进行相加,得到每一步的最小费用,最后将所用费用相加。例如,给定一个数列 {2,4,5,3,7,9},构造哈夫曼树的过程如下:
- 选择最小的两个数 2 和 3,将 2 和 3 删除并将他们的和 5 加入数列,得到 {5,4,5,7,9},这一步的费用为 2 + 3 = 5;
- 选择最小的两个数 4 和 5,将 4 和 5 删除并将他们的和 9 加入数列,得到 {9,5,7,9},这一步的费用为 4 + 5 = 9;
- 选择最小的两个数 5 和 7,将 5 和 7 删除并将他们的和 12 加入数列,得到 {9,12,9},这一步的费用为 5 + 7 = 12;
- 选择最小的两个数 9 和 9,将 9 和 9 删除并将他们的和 18 加入数列,得到 {18,12},这一步的费用为 9 + 9 = 18;
- 选择最小的两个数 18 和 12,将 18 和 12 删除并将他们的和 30 加入数列,得到 {30},这一步的费用为 18 + 12 = 30;
- 数列 {30} 只有一个元素,构造完成,总费用 5 + 9 + 12 + 18 + 30 = 74。
(3)代码:
public class HuffmanTree {
public static int minCost(int[] array, int cost){
if(array.length == 1)
return cost;
int min1 = 0, min2 = 0;
Arrays.sort(array);
min1 = array[0];
min2 = array[1];
int[] temp = new int[array.length - 1];
for (int i = 0; i < temp.length - 1; i++) {
temp[i] = array[i + 2];
}
temp[temp.length - 1] = min1 + min2;
cost = cost + min1 + min2;
return minCost(temp, cost);
}
public static void main(String[] args) {
int[] array = {2, 4, 5, 3, 7, 9};
System.out.println(minCost(array, 0));
}
}