一.贪心算法的基本概念
当一个问题具有最优子结构性质时,我们会想到用动态规划法去解它。但有
时会有更简单有效的算法。我们来看一个找硬币的例子。假设有四种硬币,它
们的面值分别为二角五分、一角、五分和一分。现在要找给某顾客六角三分钱。
这时,我们会不假思索地拿出 2 个二角五分的硬币,1 个一角的硬币和 3 个一
分的硬币交给顾客。这种找硬币方法与其他的找法相比,所拿出的硬币个数是
最少的。这里,我们下意识地使用了这样的找硬币算法:首先选出一个面值不
超过六角三分的最大硬币,即二角五分;然后从六角三分中减去二角五分,剩
下三角八分;再选出一个面值不超过三角八分的最大硬币,即又一个二角五分,
如此一直做下去。这个找硬币的方法实际上就是贪心算法。顾名思义,贪心算
法总是作出在当前看来是最好的选择。也就是说贪心算法并不从整体最优上加
以考虑,它所作出的选择只是在某种意义上的局部最优选择。当然,我们希望
贪心算法得到的最终结果也是整体最优的。上面所说的找硬币算法得到的结果
就是一个整体最优解。找硬币问题本身具有最优子结构性质,它可以用动态规
划算法来解。但我们看到,用贪心算法更简单,更直接且解题效率更高。这利
用了问题本身的一些特性。例如,上述找硬币的算法利用了硬币面值的特殊性。
如果硬币的面值改为一分、五分和一角一分 3 种,而要找给顾客的是一角五分
钱。还用贪心算法,我们将找给顾客 1 个一角一分的硬币和 4 个一分的硬币。
然而 3 个五分的硬币显然是最好的找法。虽然贪心算法不是对所有问题都能得
到整体最优解,但对范围相当广的许多问题它能产生整体最优解。如图的单源
最短路径问题,最小生成树问题等。在一些情况下,即使贪心算法不能得到整
体最优解,但其最终结果却是最优解的很好的近似解。
二.求解活动安排问题算法
活动安排问题是可以用贪心算法有效求解的一个很好的例子。该问题要求高
效地安排一系列争用某一公共资源的活动。贪心算法提供了一个简单、漂亮的
方法使得尽可能多的活动能兼容地使用公共资源。
设有 n 个活动的集合 e={1,2,…,n},其中每个活动都要求使用同一资
源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。每个活动 i
都有一个要求使用该资源的起始时间 si 和一个结束时间 f
i
,且 s
i
<f
i
。如果选择了
活动 i,则它在半开时间区间[s
i
,f
i
]内占用资源。若区间[s
i
,f
i
]与区间[s
j
,f
j
]不
相交,则称活动 i 与活动 j 是相容的。也就是说,当 s
i
≥ 或 s
j
≥f
j
时,活动 i 与
活动 j 相容。活动安排问题就是要在所给的活动集合中选出最大的相容活动子
集合。
在下面所给出的解活动安排问题的贪心算法 gpeedyselector 中,各活动的
起始时间和结束时间存储于数组 s 和 f{中且按结束时间的非减序:.
f1≤f2≤…≤fn 排列。如果所给出的活动未按此序排列,我们可以用 o(nlogn)
的时间将它重排。
template< class type>