贪心算法Java实现
贪心算法介绍
贪心算法(贪婪算法)是一个遵循启发式解决问题的算法范式,核心思想是通过在每一步的选择中都选用当前步骤下最优的选择,期望结果是最优的算法。贪心算法得到的结果不一定是最优结果,但是都是相对接近最优解的结果。
步骤
- 建立问题的数学模型,并构建一个备选答案区;
- 把待求解的问题分成多个子问题;
- 使用一个选择函数对每个子问题求得最优解,并判断是否可以用于整个问题;
- 把所有子问题的最优解合成一个整个问题的解。
应用场景
贪心算法可以用来求最小生成树、哈夫曼编码、集合覆盖问题等。
使用实例
- 假设存在下标中的需要付费的广播台,以及广播台信号可以覆盖的地区,这样选择最少的广播台让所有地区都可以接收到信息。
广播台 | 覆盖地区 |
---|---|
K1 | 北京,上海,天津 |
K2 | 广州,北京,深圳 |
K3 | 成都,上海,杭州 |
K4 | 上海,天津 |
K5 | 杭州,大连 |
- 解决方案
-
使用穷举列出每个可能的广播台的集合,假设总有有n个广播台,则广播台组合总共有2n-1个。
-
使用贪心算法获取近似解,选择策略上,需要选择覆盖所有地区的最小集合,步骤如下。
- 遍历所有广播台,找到一个覆盖了最多还没有被覆盖地区的电台,这个电台可能包含已经覆盖了地区,可以忽略;
- 把这个电台放入到一个集合中,在下次比较时去掉该电台覆盖的地区;
- 重复前两个步骤直到覆盖了全部地区。
- 参考代码
import java.util.*;
public class Greedy {
//创建广播台
Map<String, HashSet<String>> broadcasts = new HashMap<>();
//添加各个电台
HashSet<String> set1 = new HashSet<>(Arrays.asList("北京", "上海", "天津"));
HashSet<String> set2 = new HashSet<>(Arrays.asList("广州", "北京", "深圳"));
HashSet<String> set3 = new HashSet<>(Arrays.asList("成都", "上海", "杭州"));
HashSet<String> set4 = new HashSet<>(Arrays.asList("上海", "天津"));
HashSet<String> set5 = new HashSet<>(Arrays.asList("杭州", "大连"));
broadcasts.put("K1", set1);
broadcasts.put("K2", set2);
broadcasts.put("K3", set3);
broadcasts.put("K4", set4);
broadcasts.put("K5", set5);
//存放所有地区
HashSet<String> allAreas = new HashSet<>(Arrays.asList("北京", "上海", "天津", "广州", "深圳", "成都", "杭州", "大连"));
//存放选择的电台
List<String> selects = new ArrayList<>();
//定义一个临时的集合存放遍历过程中的电台覆盖的地区和当前还没有覆盖的地区的交集
HashSet<String> tempSet = new HashSet<>();
//定义maxKey,保存在一次遍历过程中,能够覆盖最大未覆盖地区对应的电台的key
String maxKey = null;
//如果allAreas不为0,就说明还有地区没有被覆盖
while(allAreas.size() != 0) {
//每次清理maxKey和tempSet
maxKey = null;
for (String key:broadcasts.keySet()) {
tempSet.clear();
//当前Key能够覆盖的地区
HashSet<String> areas = broadcasts.get(key);
tempSet.addAll(areas);
//求出tempSet和allAreas集合的交集,重新赋值给tempSet
tempSet.retainAll(allAreas);
//如果当前集合包含的未覆盖地区的数量比maxKey指向的集合地区还多,需要重新修改maxKey
if (tempSet.size() > 0 && (maxKey == null || tempSet.size() > broadcasts.get(maxKey).size())) {
maxKey = key;
}
}
//如果maxKey不为空,就添加到selects,并将maxKey的电台从需要覆盖的电台中移除
if (maxKey != null) {
selects.add(maxKey);
allAreas.removeAll(broadcasts.get(maxKey));
}
}
System.out.println("得到的选择结果是" + selects);
}