图解算法学习笔记(八):贪婪算法

目录

(1)背包问题

(2)集合覆盖问题

(3)NP完全问题

(4)小结


本章内容:

  • 学习如何处理没有快速算法的问题(NP完全问题)。
  • 学习近似算法,使用它们找到NP问题的近似解。
  • 学习贪婪策略。

(1)背包问题

假设你是个贪婪的小偷,背着可装35磅重东西的背包,在商场伺机盗窃各种可装入背包的商品。你力图往背包中装入价值最高的商品,你会使用哪种算法呢?你可使用贪婪策略:先盗窃可装入背包的最贵商品,再盗窃还可装入背包的最贵商品。但是此次这种贪婪策略可不好使了,例如,你可盗窃的商品有下面三种。

你的背包可装入35磅的东西,音响再贵,你把它给偷了,但背包没有空间装其他东西了。

你偷到了价值3000美元的东西。且慢!如果不是偷音响,而是投笔记本电脑和吉他,总价值为3500美元!

在这里,贪婪策略显然不能获得最优解,但非常接近。下一章将介绍如何找出最优解。

(2)集合覆盖问题

假设你办了个广播节目,要让全美50个州的听众都收听的到。为此,你需要决定在哪些广播台播出。在每个广播台播出都需要支付费用,因此你力图在尽可能少的广播台播出。现有广播台名单和每个广播台覆盖的区域。

如何找出覆盖全美50个州的最小广播台集合?解法为列出所有可能的集合,在这些集合中选出覆盖全美50个州的最小集合。我们需要计算每个可能的子集需要的时间。这非常耗时。

近似解法:

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

这是一种近似算法。判断近似算法优劣的标准如下:

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

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

# You pass an array in, and it gets converted to a set.
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_stations = set()

while states_needed:
  best_station = None
  states_covered = set()
  #一次for循环找出最佳best_station,知道states_needed为空
  for station, states in stations.items():
    covered = states_needed & states
    if len(covered) > len(states_covered):
      best_station = station
      states_covered = covered

  states_needed -= states_covered
  final_stations.add(best_station)

print(final_stations)

(3)NP完全问题

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

前往5个城市时,可能的路径有120条。这就是NP完全问题,需要计算所有可能的路径。

如何识别NP完全问题:

NP完全问题无处不在!如果能够判断一个问题属于NP完全问题,就不用去寻找完美的解决方案!而是使用近似算法即可。以下条件可帮助判断问题是不是NP完全问题。

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

(4)小结

  • 贪婪算法寻找局部最优解,企图以这种方式获得全局最优解。
  • 对于NP完全问题,还没有找到快速解决的方案。
  • 面临NP完全问题时,最佳的做法是使用近似算法。
  • 贪婪算法易于实现,运行速度快,是不错的近似算法。

猜你喜欢

转载自blog.csdn.net/cg129054036/article/details/83716736