【算法图解】 之 [贪婪算法(贪心算法)] 详解

入门算法学习,看的第一本是深入浅出的《算法图解》一书,本博客是对《算法图解》一书的学习笔记,将书中的分享的算法示例用Python3语言实现。
如果你也想要阅读这本书,百度云盘链接:https://pan.baidu.com/s/1s967vfgEBd1vSrfwVI9Y3g 提取码:【be9k】
或者也可以留言你的邮箱,我将PDF共享给你~

贪婪算法

  • 贪婪算法(又称贪心算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
  • 贪婪算法很简单:每步都采取最优的做法。用专业术语说,就是你每步都选择局部最优解,最终得到的就是全局最优解。

贪婪算法工作原理

在这里插入图片描述
在这里插入图片描述
你希望在这间教室上尽可能多的课。如何选出尽可能多且时间不冲突的课程呢?

这个问题好像很难,不是吗?实际上,算法可能简单得让你大吃一惊。具体做法如下。

  • (1) 选出结束最早的课,它就是要在这间教室上的第一堂课。

  • (2) 接下来,必须选择第一堂课结束后才开始的课。同样,你选择结束最早的课,这将是要在这间教室上的第二堂课。

  • 重复这样做就能找出答案!下面来试一试。美术课的结束时间最早,为10:00 a.m.,因此它就是第一堂课。
    在这里插入图片描述

  • 英语课不行,因为它的时间与美术课冲突,但数学课满足条件。最后,计算机课与数学课的时间是冲突的,但音乐课可以。
    在这里插入图片描述

很多人都说,这个算法太容易、太显而易见,肯定不对。但这正是贪婪算法的优点——简单易行!

贪婪算法很简单:每步都采取最优的做法。在这个示例中,你每次都选择结束最早的课。用专业术语说,就是你每步都选择局部最优解,最终得到的就是全局最优解。

贪婪算法–案例

在这里插入图片描述
每个广播台都覆盖特定的区域,不同广播台的覆盖区域可能重叠。
在这里插入图片描述
如何找出覆盖全美50个州的最小广播台集合呢?听起来很容易,但其实非常难。具体方法如下。

  • (1) 列出每个可能的广播台集合,这被称为幂集(power set)。可能的子集有2n
    个。
    在这里插入图片描述
  • (2) 在这些集合中,选出覆盖全美50个州的最小集合。
    • 问题是计算每个可能的广播台子集需要很长时间。由于可能的集合有2n个,因此运行时间为O(2n)。如果广播台不多,只有5~10个,这是可行的。
    • 但如果广播台很多,结果将如何呢?
    • 随着广播台的增多,需要的时间将激增。假设你每秒可计算10个子集,所需的时间将如下。
      在这里插入图片描述

没有任何算法可以足够快地解决这个问题!怎么办呢?

贪婪算法可化解危机!使用下面的贪婪算法可得到非常接近的解。

  • (1) 选出这样一个广播台,即它覆盖了最多的未覆盖州。即便这个广播台覆盖了一些已覆盖的州,也没有关系。
  • (2) 重复第一步,直到覆盖了所有的州。
  • 这是一种近似算法(approximation algorithm)。在获得精确解需要的时间太长时,可使用近似算法。

判断近似算法优劣的标准如下:

  • 速度有多快;
  • 得到的近似解与最优解的接近程度。

贪婪算法是不错的选择,它们不仅简单,而且通常运行速度很快。在这个例子中,贪婪算法
的运行时间为O(n^2),其中n为广播台数量。

下面是解决这个问题的代码。

state_needed = {'mt', 'wa', 'or', 'id', 'nv', 'ut', 'ca', 'az'}  # 需要覆盖的州的集合

stations = {}                               # 用集合的形式记录广播台清单
stations["kone"] = {"id", "nv", "ut"}       # 表示:kone广播台可以覆盖id、nv、ut地区 
stations["ktwo"] = {"wa", "id", "mt"}       # 表示:ktwo广播台可以覆盖wa、id、mt地区 
stations["kthree"] = {"or", "nv", "ca"}
stations["kfour"] = {"nv", "ut"}
stations["kfive"] = {"ca", "az"}


finaly_stations = set()                       # 最终选择的广播台


while state_needed:                           # 循环需要覆盖的州的集合,直到覆盖完全,才停止循环

    best_station = None                       # 最合适的广播台
    best_states_covered = set()               # 记录覆盖的交集地区
    
    for station, states in stations.items():  # 遍历每一个广播台
    
        coverd = state_needed & states        # covered包含同时出现在‘需要覆盖’的和‘广播站覆盖’的那些州
        
        if len(coverd) > len(best_states_covered): # 检查该广播台覆盖的州是否比best_states_coverd 多
        
            best_station = station                  # 如果多,就选择这个station为最合适的广播台 

            best_states_covered = coverd            # 记录这次覆盖的交集地区

            state_needed -= coverd                  # 减少下次需要覆盖的地区
            
            finaly_stations.add(best_station)       # 将这个最优广播站添加到finaly_stations集合中



print(finaly_stations)

----------------------
{'kone', 'kfive', 'kthree', 'ktwo'}

运行时间

在这里插入图片描述

  • 6
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
贪心算法(Greedy Algorithm)是一种常见的算法思想,其核心思想是在每一步选择中都采取当前状态下最好或最优(即最有利)的选择,从而希望最终得到全局最好或最优的解。贪心算法的特点是只考虑当前状态,不考虑以后的影响。 贪心算法的应用范围非常广泛,例如最小生成树、最短路径、背包问题等等。下面以活动安排问题为例,来详细讲解贪心算法的思想和实现过程。 问题描述: 有n个活动,每个活动都有一个开始时间和结束时间,你作为一个活动组织者需要安排这些活动的时间,保证每个活动的时间不重叠,问最多能安排多少个活动? 解题思路: 对于每个活动,我们只需要选择结束时间最早的活动,然后排除掉与该活动时间重叠的其他活动,继续选择结束时间最早的活动,直到所有活动都被选择完毕。这就是贪心算法的思想。 解题步骤: 1. 将所有活动按照结束时间从小到大排序。 2. 选择第一个活动,并将该活动的结束时间作为当前时间。 3. 遍历所有活动,选择结束时间大于等于当前时间的活动,并将该活动的结束时间作为当前时间。 4. 重复步骤3,直到遍历完所有活动。 代码实现: ```python def activity_selection(s, f): n = len(s) selected = [] i = 0 selected.append(i) for j in range(1, n): if s[j] >= f[i]: selected.append(j) i = j return selected ``` 其中s是所有活动的开始时间,f是所有活动的结束时间,selected是最终选择的活动序号列表。 时间复杂度分析: 对所有活动按照结束时间排序的时间复杂度为O(nlogn),遍历每个活动的时间复杂度为O(n),因此总时间复杂度为O(nlogn)。 参考资料: [1] 《算法导论》(第三版)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值