0
点赞
收藏
分享

微信扫一扫

算法-常用10种算法005-贪心算法(详细图解,附代码)


贪心算法

目录

  • ​​贪心算法​​
  • ​​贪心算法介绍​​
  • ​​贪心算法最佳应用-集合覆盖​​
  • ​​思路:​​
  • ​​使用贪心算法,效率高:​​
  • ​​分析的图解​​
  • ​​代码分析​​
  • ​​核心代码​​
  • ​​贪心算法注意事项和细节​​
  • ​​完整代码​​

贪心算法介绍

  1. 贪心算法(贪婪算法)是指对问题进行求解时,**在每一步种都采用最好或者最优(最有利)的选择,**而希望能够导致结果最好或者最优的算法.
  2. 贪心算法所得到的结果不一定时最优的结果(有时候是最优解),但是都是相对近似(接近)最优的结果.

贪心算法最佳应用-集合覆盖

  • 假设存在如下表的需要付费的广播台, 以及广播台信号可以覆盖的地区。 如何选择最少的广播台,让所有的地区都可以接收到信号

广播台

覆盖地区

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年

使用贪心算法,效率高:

  1. 目前没有算法可以快速计算的准备的值,使用贪婪算法,则可以得到非常接近的解,并且效率高.选择策略上,需要覆盖全部地区的最最小集合.
  2. 遍历所有的广播电台,找的一个覆盖了最多未覆盖的地区的电台,(此电台可能包含一些已覆盖的地区,下一步处理)
  3. 将这个电台加入到一个集合,把该电台覆盖的地区在下次比较时去掉
  4. 重复第一步,直到覆盖了全部的地区

分析的图解

  1. allAreas = { “北京”,“上海”,“天津”,“广州”,深圳",“成都”,杭州",“大连”};
    // 表示需要覆盖的所有地区
    key由K1到5,遍历所有的广播电台,找的一个覆盖了最多未覆盖的地区的电台
  2. 算法-常用10种算法005-贪心算法(详细图解,附代码)_java

  3. 建一个索引maxKey表示最大的未覆盖的地区=k1,.
  4. 将这个电台加入到一个集合,ArrayList(k1)把该电台覆盖的地区在下次比较时去掉 ,所
    allAreas = { 广州",深圳",“成都”,杭州",“大连”};

算法-常用10种算法005-贪心算法(详细图解,附代码)_数据结构_02

  1. 索引maxKey表示最大的未覆盖的地区=k2,.将这个电台加入到一个集合,ArrayList(k1,k2)
  2. 然后把k2的元素,去掉.重复第key遍历…依次类推…

算法-常用10种算法005-贪心算法(详细图解,附代码)_java_03

6.ArrayList(k1,k2,k3,k5),电台覆盖的地区在比较去掉,所以为:allAreas = { };,

算法-常用10种算法005-贪心算法(详细图解,附代码)_算法_04

代码分析

核心代码

//创建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]
}
}


举报

相关推荐

0 条评论