8贪婪算法
内容:
- 处理不能完成的任务:没有快速算法的问题(NP完全问题)
- 识别NP完全问题,以免浪费时间去寻找解决它们的快速算法
- 学习近似算法,使用它们可快速找到NP完全问题的近似解
- 学习贪婪策略—一种非常简单的问题解决策略
1.教室调度问题
假设有如下课程表,你希望将尽可能多的课程安排在某个教室
课程 | 开始时间 | 结束时间 |
美术 | 9:00 | 10:00 |
英语 | 9:30 | 10:30 |
数学 | 10:00 | 11:00 |
计算机 | 10:30 | 11:30 |
音乐 | 11:00 | 12:00 |
贪婪算法:每步采取最优的做法。步步最优,全局最优。
虽然贪婪算法并非在任何情况下都有效,但它简单易行(优点)。
2.背包问题
假设一个小偷,背着可装35斤的背包,在商场伺机盗窃各种可装入背包的商品。
- 1.盗窃可装入背包的最贵商品
- 2.再盗窃还可装入背包的最贵物品,重复
音响 | 3000元 | 30斤 |
笔记本电脑 | 2000元 | 20磅 |
吉他 | 1500元 | 15斤 |
对于小偷来说,偷到东西的价值差不多就行,没必要追求最大价值。即有些情况下,完美是优秀的敌人。有时只要找到一个能够大致解决问题的算法,那么贪婪算法正好用上。
3.集合覆盖问题
假设一个广播节目,要让全部地区听到。为此需要在哪些广播台播出。一个广播台可能包含覆盖多个地区,因此力图在最少的广播台播出。由于可能的子集有2n个,因此运行时间为O(22)。
3.1近似算法
在获得精确解需要的时间太长时,可使用近似算法。
- 1.选出这样一个广播台,即它覆盖了最多的未覆盖的州。即便这个广播台覆盖了一些已覆盖的州,也没有关系
- 2.重复第一步,直到覆盖了所有的州
判断近似算法优劣的标准如下:
- 速度有多快
- 得到的近似解与最优解的接近程度。
states_needed = set(["mt","wa","or","id","nv","ut","ca","az"])
stations = {
"kone":set(["id","nv","ut"]),
"ktwo":set(["wa","id","mt"]),
"kthree":set(["or","nv","ca"]),
"kfour":set(["nv","ut"]),
"kfive":set(["ca","az"])
}
final_stations = set()
while states_needed:
best_station = None
states_covered = set()
for station, state in stations.items():
covered = states_needed & state
if len(covered) > len(states_covered):
best_station = station
states_covered = covered
states_needed -= states_covered
final_stations.add(best_station)
print(final_stations) #{'kthree', 'kfive', 'ktwo', 'kone'}
mt | wa | or | id | nv | ut | ca | az |
1 | 1 | 1 | |||||
2 | 2 | 2 | |||||
3 | 3 | 3 | |||||
4 | 4 | ||||||
5 | 5 |
4.NP完全问题
旅行商问题:旅行商前往5个城市,如何规划,使行程最短
集合问题:
集合1 | 集合2 | 集合3 |
kone ktwo kthree ... | kten keleven ... | khundred kthoursand ... |
4.1识别NP完全问题
1.元素较少时算法的运行速度非常快,但随着元素数量的增加,速度会变得非常慢。
2.设计所有组合的问题通常是NP完全问题。
3.不能将问题分成小问题,必须考虑各种可能的情况。这可能是NP完全问题。
4.如果问题设计序列(如旅行商问题中的城市序列)且难以解决,它可能是NP完全问题。
5.如果问题涉及集合(如广播台集合)且难以解决,它可能就是NP完全问题。
6.如果问题可转换为集合覆盖问题或旅行商问题,那它肯定是NP完全问题。
5.总结
- 贪婪算法寻找局部最优解,企图以这种方式获得全局最优解。
- 对于NP完全问题,还没有找到快速解决方案。
- 面临NP完全问题时,最佳的做法是使用近似算法。
- 贪婪算法易于实现、运行速度快,是不错的近似算法。