贪婪算法

1、概念

贪婪算法: 每步都采取最优的做法。
优点: 简单易行。
特点: 得到的结果是最优解或者与最优解相当接近。所以也不是任何情况下行之有效的。可以看成是一个近似算法。

2、教室课表调度问题

课程表如下,如何选出尽可能多且时间不冲突的课程呢?

英语8 :00 AM9:00 AM
思修8:30 AM9:30 AM
C语言9:00 AM10:00 AM
计算机概论9:40 AM10:40 AM
Python10:20 AM11:20 AM

贪婪算法做法具体如下:

  1. 选出最早结束的课,就是要在这间教室上的第一堂课。
  2. 接下来,必须选择第一堂课后才开始的课。同样,选择最早结束的课,这将是要在这间教室上的第二堂课。以此类推。

最终贪婪算法求出这间教室课表安排顺序为: 英语、C语言、Python。

3、背包问题

举例背包问题主要讨论贪婪算法并非是在任何情况下行之有效的。

假设你是一个小偷,你背着可装35磅重东西的背包,在商场伺机盗窃各种可装入背包的商品。商场的商品重量和价格如下:

商品名价格重量
音响6000美元30磅
笔记本电脑4000美元20磅
吉他3000美元15磅

采用贪婪策略,具体做法如下:

  1. 盗窃可装入背包的最贵商品。
  2. 再盗窃还可装入背包的最贵商品,以此类推。

采用贪婪策略求出只偷到了6000美元的东西,但是如果不偷音响,而是偷笔记本和吉他,那将偷到7000美元的东西。

启示:

在某些情况下,完美是优秀的敌人。有时候,你只需要找到一个能够大致解决问题的算法,此时贪婪算法正好可派上用场,因为他们实现起来很容易,得到的结果又与正确结果相当接近。

4、集合覆盖问题

假设你办了一个广播节目,要让全国的听众都能收听得到,为此你需要决定在哪些广播台播出,在每个广播台都需要支付费用,因此你力图在尽可能少的广播台播出,然而每个广播台都覆盖特定的区域,不同广播台的覆盖区域可能重叠。如何找出覆盖全国34个省级区域的最小广播台集合呢?看起来很简单,但实现起来非常难。具体方法如下:

  1. 列出每个可能的广播台集合,这个被称为幂集,可能的子集为 2 n 2^n 2n 个。
  2. 在这些集合中,选出覆盖全中国34个省级区域的最小集合。

此时问题来了,这时算法的运行时间为 O ( 2 n ) O(2^n) O(2n) ,如果广播台很多,没有任何算法能足够快地解决这个问题。怎么办呢?
贪婪算法可以化解危机,使用贪婪算法可以得到非常接近的解。
使用贪婪算法步骤如下:

  1. 选出这样一个广播台,即它覆盖了最多未覆盖州。即便这个广播台覆盖了一些已覆盖的省级区域,也没有关系。
  2. 重复第一步,直到覆盖了所有的省级区域。

这个算法的运行时间为 O ( n 2 ) O(n^2) O(n2),其中n为广播台数量。

代码(Python3):
  1. 出于简化考虑,假设省级区域只有江西省、广东省、湖北省、福建省、广西省、云南省、四川省、山东省。可以创建一个列表,其中包含要覆盖的省级区域。

    states_needed = set(['江西省','广东省','湖北省','福建省','广西省','云南省','四川省','山东省']) #传入一个列表,将其转换为集合
    
  2. 广播台清单,使用散列表来表示。

    stations = {}
    stations['频道1'] = set(['江西省','广东省','福建省'])
    stations['频道2'] = set(['四川省','山东省','广西省'])
    stations['频道3'] = set(['山东省','湖北省','福建省'])
    stations['频道4'] = set(['云南省','湖北省','江西省'])
    
  3. 最后使用一个集合来存储最终选择的广播台。

    final_stations = set()
    
  4. 开始计算,遍历所有的广播台,从中选择覆盖了最多的未覆盖的广播台。将这个广播台存储在best_station中。把该广播台覆盖的所有未覆盖的省级区域放入states_covered集合。for循环每个广播台,并确定它是否是最佳的广播台。for循环结束后将best_station添加到最终的广播台列表中。

    best_station = None
    states_covered = set()
    for station,states_for_station in stations.items():
    	covered = states_needed & states_for_station #取交集
    	if len(covered) > len(states_covered):
    		best_station = station
    		states_covered = covered
    final_station.add(best_station)
    
  5. 由于覆盖了一些省级区域,因此不需要覆盖这些省级区域,还需更新states_needed。

    states_needed -= states_covered 
    
  6. 不断循环,直到states_needed 为空,这个循环完整代码:

    while states_needed:
    	best_station = None
    	states_covered = set()
    	for station,states_for_station in stations.items():
    		covered = states_needed & states_for_station #取交集
    		if len(covered) > len(states_covered):
    			best_station = station
    			states_covered = covered
    	states_needed -= states_covered 
    	final_stations.add(best_station)		
    
  7. 最后打印final_stations,输出:
    在这里插入图片描述

5、NP完全问题

NP完全问题: 多项式复杂程度的非确定性问题,简单的理解就是 “难解”,需要计算所有的解,并从中选出最小/最短的那个。所以对于NP完全问题,一般采用近似求解,采用算法如:贪婪算法

判断是否为NP完全问题:

  1. 元素较少时算法运行的速度非常快,但随着元素数量的增加,速度会变得非常慢,这时可能是NP完全问题。
  2. 涉及”所有组合“的问题通常是NP问题。
  3. 不能将问题分成小问题,必须考虑各种可能的情况。这个可能是NP完全问题。
  4. 如果问题涉及序列(旅行商问题中的城市序列)且难以解决,它可能就是NP完全问题。
  5. 如果问题涉及集合(如广播集合)且难以解决,它可能就是NP完全问题。
  6. 如果问题可转换未集合覆盖或旅行商问题,那它肯定是NP完全问题。

6、总结

  • 贪婪算法寻找局部最优解,企图以这种方式获取全局最优解。
  • 对于NP完全问题,还没有找到快速解决的方案。
  • 面临NP完全问题,最佳的做法是使用近似算法。
  • 贪婪算法易于实现、运行速度快,是不错的近似算法。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值