菜鸟学算法--贪婪算法

目录

什么是贪婪算法

集合覆盖问题


什么是贪婪算法

贪婪算法很简单:每步都采取最优的做法。用专业术语说,就是每步都选择局部最优解,最终得到的就是全局最优解。

集合覆盖问题

假设你办了个广播节目,要让每个地方的听众都收听得到。为此,你需要决定在哪些广播台播出。在每个广播台播出都需要支付费用,因此你力图在尽可能少的广播台播出。现有广播台名单如下。

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"])

每个广播台都覆盖特定的区域,不同广播台的覆盖区域可能重叠。如何找出覆盖全美50个州的最小广播台集合呢?地点如下。

states_needed = set(["mt", "wa", "or", "id", "nv", "ut","ca", "az"]) #将要覆盖的州

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

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

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

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

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

while states_needed: #如果还有未覆盖的
    best_station = None
    states_covered = set() #已覆盖的集合
    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) #添加已选择的电台

正确的解可能有多个。你需要遍历所有的广播台,从中选择覆盖了最多的未覆盖州的广播台。我将这个广播台存储在best_station 中。

states_covered 是一个集合,包含该广播台覆盖的所有未覆盖的州。 for 循环迭代每个广播台,并确定它是否是最佳的广播台。下面来看看这个 for 循环的循环体。

covered 是一个集合,包含同时出现在 states_needed 和states_for_station 中的州;换言之,它包含当前广播台覆盖的
一系列还未覆盖的州!接下来,你检查该广播台覆盖的州是否比best_station 多。

如果是这样的,就将 best_station 设置为当前广播台。最后,你在 for 循环结束后将best_station 添加到最终的广播台列表中。

你还需更新 states_needed 。由于该广播台覆盖了一些州,因此不用再覆盖这些州。

最后,你打印 final_stations ,结果类似于下面这样。

print(final_stations)

菜鸟学算法--贪婪算法_第1张图片

结果符合你的预期吗?选择的广播台可能是2、3、4和5,而不是预期的1、2、3和5。两个皆可

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