S5-算法-贪心算法【2021-02-07】

总目录:地址如下看总纲

https://www.jianshu.com/p/929ca9e209e8

1、应用场景-集合覆盖问题

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


image.png

2、贪心算法介绍

(1)贪婪算法(贪心算法)是指在对问题进行求解时,在每一步选择中都采取最好或者最优(即最有利)的选择,从而希望能够导致结果是最好或者最优的算法

(2)贪婪算法所得到的结果不一定是最优的结果(有时候会是最优解),但是都是相对近似(接近)最优解的结果
(如果价格,考虑的话,那么可能对于价格,做不到最优;只有方案配对最优【毕竟不是综合考虑的】)

3、解决方案(举例两类:穷举法,贪心算法)

(1)穷举法:
如何找出覆盖所有地区的广播台的集合呢,使用穷举法实现,列出每个可能的广播台的集合,这被称为幂集。假设总的有n个广播台,则广播台的组合总共有�2ⁿ -1 个,假设每秒可以计算10个子集, 如图:


image.png

(2)贪心算法最佳应用-集合覆盖的思路分析:

目前并没有算法可以快速计算得到准备的值, 使用贪婪算法,则可以得到非常接近的解,并且效率高。选择策略上,因为需要覆盖全部地区的最小集合,具体步骤如下:

<1>遍历所有的广播电台, 找到一个覆盖了最多未覆盖的地区的电台(此电台可能包含一些已覆盖的地区,但没有关系)--- 此集合大多时候是一个 或者 多个组合的 集合 ,这里的 "个" 指的是广播台 K1,K2....

<2>将这个电台加入到一个集合中(比如ArrayList), 想办法把该电台覆盖的地区在下次比较时去掉

<3>重复第1步直到覆盖了全部的地区

4、贪心算法图解:

说明:
allAreas 为需要覆盖所有广播台内的地区,
selects = ArrayList () 为最终集合(将需要被覆盖的广播台集合汇总)
maxKey 指向当前 包含 地区最多的广播台,若大小一样依照顺序(用于剔除 allAreas 中的地区,符合就剔除)
key 用于指向每一个广播台,依次移动 查询 和 allAreas 中的覆盖地区个数

步骤:
(1)刚开始 selects 没有任何广播台 ,allAreas 列出所有(暂时未被剔除),k1 到 k5 覆盖地区个数分别为
3,3,3,2,2


image.png

(2)当 maxKey 指向 k1 后,K1 装入 selcts 集合 ,K1 中的地区 剔除匹配到 allAreas 中的地区


image.png

(3)此时个数最大的是 k2,k3,k5 ,按照顺序优先指向 K2 。然后开始如上操作, maxKey 指向 K2,K2装入 selects集合, K2 中的地区 剔除 匹配到 allAreas 中的地区


image.png

(4)此时地区个数最大的广播台是 k3 , k5 按照顺序 优先 k3。同上 ,maxKey 指向 k3, k3 装入 selects 集合, k3 中的地区匹配到 allAreas 中的地区 并剔除


image.png

(5)此时最大地区个数只有 k5 ,同,maxKey 指向 k5 ,k5 装入 selects 集合,k5 中的地区匹配到 allAreas中的地区并 剔除,此时所有都已经覆盖到, selects 为最终


image.png

5、贪心算法代码实现


/*
 * @Description:    贪心算法 -- 实现广播问题
 * @Author:         阿K
 * @CreateDate:     2021/2/7 16:30
 * @Param:          
 * @Return:          
**/
public class GreedyAlgorithm {
    public static void main(String[] args) {
        // 创建用于存放所有广播电台的 map
        HashMap<String, HashSet<String>> broadcasts = new HashMap<> ( );

        //将各个电台放入到broadcasts
        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 ("大连");
        //加入到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 = obtainAllAreas (broadcasts);

        //创建ArrayList, 存放选择的电台集合(最终答案)
        ArrayList<String> selects = new ArrayList<> ( );

        //定义一个临时的集合, 在遍历的过程中,存放遍历过程中的电台覆盖的地区和当前还没有覆盖的地区的交集
        HashSet<String> tempSet = new HashSet<> ( );// 可以理解为不断变动的 allAreas

        // 定义maxKey , 保存在一次遍历过程中,能够覆盖最大未覆盖的地区对应的电台的key
        // 若 maxKey 不为null ,则会加入到 selects
        String maxKey = null;

        while (allAreas.size ( ) != 0) {// 若 allAreas 不为 0,则表示还没有覆盖到所有地区(既没有全部剔除完)

            // maxKey 每次重新指向,都需要重置一次
            maxKey = null;

            // 遍历 broadcasts, 取出对应key
            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
                // tempSet.size() >broadcasts.get(maxKey).size()) 体现出贪心算法的特点,每次都选择最优的
                if (tempSet.size ( ) > 0 && (maxKey == null || tempSet.size ( ) > broadcasts.get (maxKey).size ( ))) {
                    maxKey = key;
                }
            }

            // maxKey != null, 就应该将maxKey 加入selects
            if (maxKey != null) {
                selects.add (maxKey);
                // 将maxKey指向的广播电台覆盖的地区,从 allAreas 去掉(剔除)
                allAreas.removeAll (broadcasts.get (maxKey));
            }
        }

        System.out.println ("得到的选择结果是" + selects);//[K1,K2,K3,K5]
    }

    // 获取所有广播电台地区
    private static HashSet<String> obtainAllAreas(HashMap<String, HashSet<String>> broadcasts) {
        if (broadcasts != null && broadcasts.size ( ) > 0) {

            HashSet<String> allAreas = new HashSet<> ( );
            Set<String> keys = broadcasts.keySet ( );
            for (String key : keys) {
                HashSet<String> all = broadcasts.get (key);
                for (String region : all) {
                    // 因 HashSet 会覆盖,所以无需判断
                    allAreas.add (region);
                }
            }
            return allAreas;
        }
        return null;
    }
}

6、贪心算法注意事项和细节

(1)贪心算法所得到的结果不一定是最优的结果(有时候会是最优解),但是都是相对近似(接近)最优解的结果
(2)比如上题的算法选出的是K1, K2, K3, K5,符合覆盖了全部的地区
(3)但是我们发现 K2, K3,K4,K5 也可以覆盖全部地区,如果K2 的使用成本低于K1,那么我们上题的 K1, K2, K3, K5 虽然是满足条件,但是并不是最优的

7、仓库坐标

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容