贪心算法
目录
- 贪心算法
- 贪心算法介绍
- 贪心算法最佳应用-集合覆盖
- 思路:
- 使用贪心算法,效率高:
- 分析的图解
- 代码分析
- 核心代码
- 贪心算法注意事项和细节
- 完整代码
贪心算法介绍
- 贪心算法(贪婪算法)是指对问题进行求解时,**在每一步种都采用最好或者最优(最有利)的选择,**而希望能够导致结果最好或者最优的算法.
- 贪心算法所得到的结果不一定时最优的结果(有时候是最优解),但是都是相对近似(接近)最优的结果.
贪心算法最佳应用-集合覆盖
- 假设存在如下表的需要付费的广播台, 以及广播台信号可以覆盖的地区。 如何选择最少的广播台,让所有的地区都可以接收到信号
广播台 | 覆盖地区 |
k1 | “北京”,“上海”,“天津” |
k2 | “广州”,“上海”,“深圳” |
k3 | “成都”,“上海”,“杭州” |
k4 | “上海”,“天津” |
k5 | “杭州”,“大连” |
思路:
- 使用穷举法实现,列出每一个可能出现的广播台的集合,这被称为幂集。 假设总的有 n 个广播台, 则广播台的组合总共有 设总的有 n 个广播台, 则广播台的组合总共有
广播台的数量n | 子集的总数量2^n | 需要的时间 |
5 | 32 | 3.2秒 |
10 | 1024 | 102.4秒 |
32 | 4294967296 | 13.6年 |
100 | 1.26*100^(30) | 4*10^23年 |
使用贪心算法,效率高:
- 目前没有算法可以快速计算的准备的值,使用贪婪算法,则可以得到非常接近的解,并且效率高.选择策略上,需要覆盖全部地区的最最小集合.
- 遍历所有的广播电台,找的一个覆盖了最多未覆盖的地区的电台,(此电台可能包含一些已覆盖的地区,下一步处理)
- 将这个电台加入到一个集合,把该电台覆盖的地区在下次比较时去掉
- 重复第一步,直到覆盖了全部的地区
分析的图解
- allAreas = { “北京”,“上海”,“天津”,“广州”,深圳",“成都”,杭州",“大连”};
// 表示需要覆盖的所有地区
key由K1到5,遍历所有的广播电台,找的一个覆盖了最多未覆盖的地区的电台 - 建一个索引maxKey表示最大的未覆盖的地区=k1,.
- 将这个电台加入到一个集合,ArrayList(k1)把该电台覆盖的地区在下次比较时去掉 ,所以
allAreas = { 广州",深圳",“成都”,杭州",“大连”};
- 索引maxKey表示最大的未覆盖的地区=k2,.将这个电台加入到一个集合,ArrayList(k1,k2)
- 然后把k2的元素,去掉.重复第key遍历…依次类推…
6.ArrayList(k1,k2,k3,k5),电台覆盖的地区在比较去掉,所以为:allAreas = { };,
代码分析
核心代码
//创建ArrayList, 存放选择的电台集合
ArrayList<String> selects = new ArrayList<String>();
//定义给maxKey , 保存在一次遍历过程中,能够覆盖最大未覆盖的地区对应的电台的key
//如果maxKey 不为null , 则会加入到 selects
String maxKey = null;
while (allAreas.size() != 0) { // 如果allAreas 不为0, 则表示还没有覆盖到所有的地区
//每进行一次while,需要索引清零
maxKey = null;
//遍历 broadcasts, 取出对应key
for (String key : broadcasts.keySet()) {
//每进行一次for
//当前这个key能够覆盖的地区
HashSet<String> areas = broadcasts.get(key);
//key能够遍历的的地区与allAreas所最大相同的东西
areas.retainAll(allAreas);
//如果当前这个集合包含的未覆盖地区的数量,比maxKey指向的集合地区还多
//就需要重置maxKey
// areas.size() >broadcasts.get(maxKey).size()) 体现出贪心算法的特点,每次都选择最优的
if (areas.size() > 0 &&
(maxKey == null || areas.size() > broadcasts.get(maxKey).size())) {
maxKey = key;
}
}
//maxKey != null, 就应该将maxKey 加入selects
if (maxKey != null) {
selects.add(maxKey);
//将maxKey指向的广播电台覆盖的地区,从 allAreas 去掉
allAreas.removeAll(broadcasts.get(maxKey));
//即broadcastsy也变称为
/**第一次遍历后
* k1 "","",""
* k2 "广州","","深圳"
* k3 "成都","","杭州"
* k4 "",""
* k5 "杭州","大连"
*/
}
}
贪心算法注意事项和细节
- 贪婪算法所得到的结果不一定是最优的结果(有时候会是最优解), 但是都是相对近似(接近)最优解的结果
- 比如上题的算法选出的是 K1, K2, K3, K5, 符合覆盖了全部的地区
- 但是我们发现 K2, K3,K4,K5 也可以覆盖全部地区, 如果 K2 的使用成本低于 K1,那么我们上题的 K1, K2, K3,K5 虽然是满足条件, 但是并不是最优的
完整代码
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
public class GreedyAlgorithm {
public static void main(String[] args) {
//创建广播电台,放入到Map
HashMap<String, HashSet<String>> broadcasts = new HashMap<String, HashSet<String>>();
//将各个电台放入到broadcasts
HashSet<String> hashSet1 = new HashSet<String>();
hashSet1.add("北京");
hashSet1.add("上海");
hashSet1.add("天津");
HashSet<String> hashSet2 = new HashSet<String>();
hashSet2.add("广州");
hashSet2.add("北京");
hashSet2.add("深圳");
HashSet<String> hashSet3 = new HashSet<String>();
hashSet3.add("成都");
hashSet3.add("上海");
hashSet3.add("杭州");
HashSet<String> hashSet4 = new HashSet<String>();
hashSet4.add("上海");
hashSet4.add("天津");
HashSet<String> hashSet5 = new HashSet<String>();
hashSet5.add("杭州");
hashSet5.add("大连");
//加入到map
broadcasts.put("K1", hashSet1);
broadcasts.put("K2", hashSet2);
broadcasts.put("K3", hashSet3);
broadcasts.put("K4", hashSet4);
broadcasts.put("K5", hashSet5);
//allAreas 存放所有的地区
HashSet<String> allAreas = new HashSet<String>();
allAreas.add("北京");
allAreas.add("上海");
allAreas.add("天津");
allAreas.add("广州");
allAreas.add("深圳");
allAreas.add("成都");
allAreas.add("杭州");
allAreas.add("大连");
//创建ArrayList, 存放选择的电台集合
ArrayList<String> selects = new ArrayList<String>();
//定义给maxKey , 保存在一次遍历过程中,能够覆盖最大未覆盖的地区对应的电台的key
//如果maxKey 不为null , 则会加入到 selects
String maxKey = null;
while (allAreas.size() != 0) { // 如果allAreas 不为0, 则表示还没有覆盖到所有的地区
//每进行一次while,需要索引清零
maxKey = null;
//遍历 broadcasts, 取出对应key
for (String key : broadcasts.keySet()) {
//每进行一次for
//当前这个key能够覆盖的地区
HashSet<String> areas = broadcasts.get(key);
//key能够遍历的的地区与allAreas所最大相同的东西
areas.retainAll(allAreas);
//如果当前这个集合包含的未覆盖地区的数量,比maxKey指向的集合地区还多
//就需要重置maxKey
// areas.size() >broadcasts.get(maxKey).size()) 体现出贪心算法的特点,每次都选择最优的
if (areas.size() > 0 &&
(maxKey == null || areas.size() > broadcasts.get(maxKey).size())) {
maxKey = key;
}
}
//maxKey != null, 就应该将maxKey 加入selects
if (maxKey != null) {
selects.add(maxKey);
//将maxKey指向的广播电台覆盖的地区,从 allAreas 去掉
allAreas.removeAll(broadcasts.get(maxKey));
//即broadcastsy也变称为
/**第一次遍历后
* k1 "","",""
* k2 "广州","","深圳"
* k3 "成都","","杭州"
* k4 "",""
* k5 "杭州","大连"
*/
}
}
System.out.println("得到的选择结果是" + selects);//[K1,K2,K3,K5]
}
}