《图解算法》阅读14—贪婪算法

  • 学会处理不可能完成的任务(NP完全问题)
  • 学习识别NP完全问题
  • 学习近似算法,使用它们可快速找到NP完全的近似解
  • 学习贪婪算法——一种非常简单的问题解决策略

教室调度问题

排课的算法如下所示。

  • 选出结束最早的课,它就是要在这间教室上的第一堂课
  • 接下来,选择第一堂课结束后才开始的课。同样,选择结束最早的课是在这间教室上的第二堂课,重复就能这一步骤,直至教室排满课程。
    这就是贪婪算法,每步都采取最优的做法,贪婪算法的优点就是简单易行。每步都是局部最优解,最后得到的是全局最优解。显然,贪婪算法并非在任何情况下都行之有效,但它易于实现。

背包问题

一个贪婪的小偷,背着可装35磅重的背包,怎样选择商品使得价值最高?贪婪算法的实现具体过程如下:
(1)盗窃可装入背包的最贵的商品
(2)再盗窃还可转入背包的最贵商品,以此类推
但是这个贪婪算法显然很多情况不是最优的。在有些情况下,完美是优秀的敌人,有时候只需要找到一个能够大致解决问题的算法,这时贪婪算法正好可以派上用场,实现起来很容易,得到的结果又与正确结果相当接近。

集合覆盖问题

如果集合有N个元素,那么集合覆盖问题的可能结果就有2的n次方。当元素的个数不是很多时,这种尝试的办法是可行的,当元素的个数很多时,运行的时间将会激增。

近似算法

贪婪算法可以得到非常近似的解。

  • 选出一个这样的广播台,即它覆盖了最多的未覆盖的州。即便这个广播台覆盖了一些已经覆盖的州,也没有关系。
  • 重复第一步,直至覆盖了所有的州。

这是一种近似算法。在获得精确解需要的时间太长的时候,可以使用近似算法。衡量近似算法优劣的原如下:

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

集合覆盖问题的算法实现如下所示。

```python
#集合覆盖问题贪婪算法
states_needed = set(["mt","wa","or","id","nv",
	"ut","ca","az"])#使用集合来表示要覆盖的州

stations = {}
stations["kone"] = set(["id","nv","ut"])
stations["ktwo"] = set(["wa","id","mt"])
stations["kthree"] = set(["or","nv","ca"])
stations["kfour"] = set(["nv","ut"])
stations["kfive"] = set(["ca","az"])

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

#遍历所有的广播台,从众选择覆盖了最多未覆盖州的广播台
#集合类似于列表,只是不能包含重复的元素,可以执行一些有趣的集合运算
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
	final_sations.add(best_station)
	states_needed -= states_covered

print(final_sations)

NP完全问题

在前面提到的旅行商问题中,旅行商需要前往5个不同的城市,需要找出前往这5个城市的最短距离,为此必须计算每条可能的路径。

旅行商问题详解

旅行商问题的可能解的数目是N的阶乘,和前面提到的集合覆盖问题有一些共同之处:我们需要计算所有的解,并从中选出最小、最短的那个,这两个问题都属于NP完全问题。
我们考虑设计一种近似求解的办法来解决这个问题。本书中作者提出了一种贪婪算法,算法的每一步都是局部最优解。随便选择出发城市,然后每次选择要去的下一个城市时,都选择没有去过的最近的城市。
NP完全问题的定义是以难解著称的问题,如旅行商和集合覆盖问题。很多聪明的人都认为,根本不可能写出可以快速解决这些问题的算法。

如何识别NP完全问题

在解决算法问题时,发现很多问题本质上就是一个问题。觉得这本书提供了一个很好的例子。
有一教练在为橄榄球队挑选队员。他列了一些对球队的要求,同时还有一份候选球员的名单,每个球员都有一些技能。如何创建一只满足所有要求的球队?这是一个集合覆盖问题。可以直接使用前面提到的贪婪算法来解决。

  • 找出符合最多要求的球员
  • 不断重复这个过程,直到所有的球队满足要求。

NP完全问题无处不在,但是要判断是不是NP完全问题很困难。易于解决的问题和NP完全问题的差别通常非常小。虽然很难,但是还是有一些规律可以寻找的。

  • 元素较少时算法的运行速度非常快,但随着元素数量的增加,速度会变得非常慢。
  • 涉及“所有组合”的问题通常是NP完全问题
  • 不能将问题分成小问题,必须考虑各种可能情况,可能是NP完全问题
  • 如果问题涉及序列且难以解决,可能是NP完全问题
  • 如果问题涉及集合且难以解决,可能是NP完全问题
  • 如果问题可转化为集合覆盖问题或旅行商问题,肯定是NP完全问题

你可能感兴趣的:(算法)