贪心算法基本介绍
应用场景
集合覆盖问题
假设存在下面需要付费的广播台,以及广播台信号可以覆盖的地区。如何选择最少的广播台,让所有的地区都可以接收到信号。
广播台 |
覆盖地区 |
K1 |
“北京”,“上海”,“天津” |
K2 |
“广州”,“北京”,“深圳” |
K3 |
“成都”,“上海”,“杭州” |
K4 |
“上海”,“天津” |
K5 |
“杭州”,“大连” |
基本介绍
- 贪心算法是指在对问题进行求解时,在每一部选择中都采取最好或最优的选择,从而希望能够导致结果是最好或者最优的算法。
- 贪心算法所得到的结果不一定是最优(有时候会是最优解)的结果,但都是相对近似(接近)最优解的结果。
贪心算法解决集合覆盖思路分析
思路分析
穷举法
如何找出覆盖所有地区的广播台的集合呢,使用穷举法实现,列出每个可能的广播台的集合,这被称为幂集。假设总共有n个广播台,则广播台的组合总共有2n-1个,假设每秒可以计算10个子集,如图:
广播台数量n |
子集总数2n |
需要的时间 |
5 |
32 |
3.2s |
10 |
1024 |
102.4s |
32 |
4294967296 |
13.6年 |
100 |
1.26*100^30 |
4*10^23年 |
随着广播台数量增加,使用穷举法实现,数值非常大,耗时也非常多,并不理想。
贪心算法
目前没有算法可以快速计算到准备的值,使用贪心算法,则可以得到非常接近的解,效率高,选择策略上,因为需要覆盖全部地区的最小集合:
- 遍历所有的广播电台,找到一个覆盖了最多未覆盖地区的电台(此电台可能包含一些已覆盖地区,但没有关系)。
- 将这些电台加入到一个集合中(比如ArrayList),想办法把该电台覆盖的地区在下次比较时去掉。
- 重复步骤1,直到覆盖了全部地区。
思路图解
key每一次执行都从k1开始依次向下扫描;
maxKey待key扫描完毕,从上面开始往下扫描,选择一个最大覆盖值(如果上下相等,优先选择上面的)
贪心算法解决集合覆盖代码实现
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| package com.algorithm.greedy;
import java.util.*;
public class GreedyAlgorithm { public static void main(String[] args) { Map<String, HashSet> broadcasts = new HashMap<>(); HashSet<String> hashSet1 = new HashSet<>(); hashSet1.add("北京"); hashSet1.add("上海"); hashSet1.add("天津"); HashSet<String> hashSet2 = new HashSet<>(); hashSet2.add("广州"); hashSet2.add("北京"); hashSet2.add("深圳"); HashSet<String> hashSet3 = new HashSet<>(); hashSet3.add("成都"); hashSet3.add("上海"); hashSet3.add("杭州"); HashSet<String> hashSet4 = new HashSet<>(); hashSet4.add("上海"); hashSet4.add("天津"); HashSet<String> hashSet5 = new HashSet<>(); hashSet5.add("杭州"); hashSet5.add("大连"); broadcasts.put("k1",hashSet1); broadcasts.put("k2",hashSet2); broadcasts.put("k3",hashSet3); broadcasts.put("k4",hashSet4); broadcasts.put("k5",hashSet5);
HashSet<String> allAreas = new HashSet<>(); allAreas.add("北京"); allAreas.add("上海"); allAreas.add("天津"); allAreas.add("广州"); allAreas.add("深圳"); allAreas.add("成都"); allAreas.add("杭州"); allAreas.add("大连"); List<String> selects = new ArrayList<>(); HashSet<String> tempSet = new HashSet<>(); HashSet<String> tempSet2 = new HashSet<>();
String maxKey = null; while(allAreas.size()!=0){ maxKey = null; for (String key : broadcasts.keySet()){ tempSet.clear(); HashSet areas = broadcasts.get(key); tempSet.addAll(areas); tempSet.retainAll(allAreas); if(tempSet.size() > 0 && (maxKey == null|| tempSet.size()>tempSet2.size())){ maxKey = key; tempSet2 = tempSet; } } if(maxKey != null){ selects.add(maxKey); allAreas.removeAll(broadcasts.get(maxKey)); } } System.out.println("所选择的结果为:"+selects); } }
|
运行结果
1 2 3
| 所选择的结果为:[k1, k2, k3, k5]
Process finished with exit code 0
|
贪心算法解决集合覆盖注意事项
- 贪心算法所得到的结果不一定是最优(有时候会是最优解)的结果,但都是相对近似(接近)最优解的结果。
- 例如上题通过算法选出的是k1,k2,k3,k5,符合覆盖了全部地区。
- 但是我们发现k2,k3,k4,k5也可以覆盖全部地区,假如k2的使用成本低于k1,那么上题的结果虽然满足条件,但并不是最优解。