贪心算法
贪心算法:在对问题求解时,总是做出在当前看来是最好的选择
是由局部到整体,算法得到的是在某种意义上的局部最优解,对整体是近似最优解
贪心算法一般按如下步骤进行:
- 建立数学模型来描述问题
- 把求解的问题分成若干个子问题
- 对每个子问题求解,得到子问题的局部最优解
- 把子问题的解局部最优解合成原来解问题的一个解(近似于最优解,也可能是最优解)
贪心算法特点是一步一步地进行,以当前情况为基础根据作当前的最优选择,通过每一步贪心选择,可得到问题的一个最优解
集合覆盖问题
一个广播覆盖问题:
存在以下广播,每个广播可以覆盖一些地区,如何选择最少的广播覆盖全部地区
广播 | 覆盖地区 |
---|---|
k1 | 北京、天津、上海 |
k2 | 广州、北京、深圳 |
k3 | 成都、上海、杭州 |
k4 | 上海、天津 |
k5 | 杭州、大连 |
解题思路
解题思路:
- 遍历所有的电台,找到覆盖了最多未覆盖地区的电台
- 将该电台放入结果集合,将该电台覆盖的地区从总地区中去除
- 重复1,2步直到总地区为空,结果集合就是我们需要的广播序列
解决步骤:
- 设置好allAreas存放所有地区,结果集合select
- 遍历所有电台找到覆盖了最多未覆盖地区的电台,第一次找是找到了k1,将k1放入select,allAreas去除k1包含的地区,去除k1
- 第2次遍历,找到覆盖了最多未覆盖地区的电台是k2,将k2放入select,allAreas去除k2包含的地区,去除k2
- 第3次遍历,找到覆盖了最多未覆盖地区的电台是k3,将k3放入select,allAreas去除k3包含的地区,去除k3
- 第4次遍历,找到覆盖了最多未覆盖地区的电台是k5,将k5放入select,allAreas去除k5包含的地区,去除k5,这个时候allAreas为空,即完全覆盖了所有地区,结束
贪心算法: 在这个问题中,贪心在与第一步,找到覆盖了最多未覆盖地区的电台,即当前情况的最优解
Java代码实现
package com.company.十种算法.greedy;
import java.util.*;
/**
* Author : zfk
* Data : 9:43
* 贪心算法 -> 集合覆盖问题
*/
public class GreedyAlgorithm {
public static void main(String[] args) {
//电台集合
HashMap<String, HashSet<String>> broadCasts = new HashMap<>();
//allAreas存放所有的地区
HashSet<String> allAreas = new HashSet<>();
//添加地区数据
add(broadCasts);
//遍历hashmap,找出所有地区放入allarea
Iterator<Map.Entry<String, HashSet<String>>> iterator = broadCasts.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<String, HashSet<String>> next = iterator.next();
HashSet<String> val = next.getValue();
val.stream().forEach(a -> allAreas.add(a));
}
allAreas.stream().forEach(a -> System.out.print(a + " "));
//贪心算法,找到近似最优解
greedyAlgorithm(allAreas,broadCasts);
}
//添加地区数据
public static void add(HashMap<String, HashSet<String>> broadCasts){
//将各个电台放入
HashSet<String> hashSet1 = new HashSet<>();
hashSet1.add("北京");
hashSet1.add("天津");
hashSet1.add("上海");
broadCasts.put("k1",hashSet1);
HashSet<String> hashSet2 = new HashSet<>();
hashSet2.add("广州");
hashSet2.add("北京");
hashSet2.add("深圳");
broadCasts.put("k2",hashSet2);
HashSet<String> hashSet3 = new HashSet<>();
hashSet3.add("成都");
hashSet3.add("上海");
hashSet3.add("杭州");
broadCasts.put("k3",hashSet3);
HashSet<String> hashSet4 = new HashSet<>();
hashSet4.add("上海");
hashSet4.add("天津");
broadCasts.put("k4",hashSet4);
HashSet<String> hashSet5 = new HashSet<>();
hashSet5.add("杭州");
hashSet5.add("大连");
broadCasts.put("k5",hashSet5);
}
/**
* 贪心算法
* @param allAreas 所有地区集合
* @param broadCasts 电台与电台所覆盖的地区集合
*/
public static void greedyAlgorithm(HashSet<String> allAreas,HashMap<String, HashSet<String>> broadCasts){
//存放选择的电台集合
ArrayList<String> select = new ArrayList<>();
//定义一个临时集合,存放遍历过程中电台覆盖的地区和当前没有覆盖地区的交集
HashSet<String> tempSet = new HashSet<>();
//maxKey,保存一次遍历过程中,能够覆盖最大地区的对应的电台
//maxKey != null,加入select
String maxKey = null;
while (allAreas.size() != 0){//allAreas不为0表示还没覆盖完全
//遍历broadcasts,取出对应的key
for (String key : broadCasts.keySet()){
//每进行一次循环,需要清空tempSet
tempSet.clear();
//当前key能覆盖的地区
HashSet<String> areas = broadCasts.get(key);
tempSet.addAll(areas);
//求出tempSet与allAreas的交集
tempSet.retainAll(allAreas);
//如果当前集合包含未覆盖地区的数量,比maxkey指向的集合地区还多
//就需要重置maxkey
if (tempSet.size() > 0 &&
(maxKey == null || tempSet.size() > broadCasts.get(maxKey).size())){
maxKey = key;
}
}
//maxKey != null,加入select
if (maxKey != null){
select.add(maxKey);
//将maxKey指向的电台覆盖的地区从allAreas中去除,把maxKey指向的电台去除
allAreas.removeAll(broadCasts.get(maxKey));
broadCasts.remove(maxKey);
//maxKey置空
maxKey = null;
}
}
System.out.println();
//当while循环结束,得到选择结果
System.out.println("选择结果:"+select);
}
}
结果: