greedy algorithm在每一步都做出在当时看起来最佳的选择,也就是,它总是做出局部最优的选择,寄希望于这样的选择能导致全局最优解。
1 活动选择问题
调度竞争共享资源的多个活动的问题,目标是选出一个最大的互相兼容的活动集合。假定有一个n个活动的集合S = {a1, a2, ..., an},这些活动使用同一个资源,而这个资源在某一时刻只能供一个活动使用。每个活动ai都有一个开始时间si和一个结束时间fi,其中0 <= si < fi < ∞。如果被选中,任务ai发生在半开时间区间[si, fi)期间。如果两个活动ai和aj满足[si, fi)和[sj, fj)不重叠,则称它们是兼容的。也就是说,若si ≥ fj或sj ≥ fi,则ai和aj是兼容的。在活动选择问题中,我们希望选出一个最大兼容活动集。假定活动已按结束时间的单调递增顺序排序:
f1 ≤ f2 ≤ f3 ≤ ... ≤ fn
例如,考虑下面的活动集合S:
对这个例子,子集{a3, a9, a11}由相互兼容的活动组成。但它不是一个最大集,因为子集{a1, a4, a8, a11}更大。实际上,{a1, a4, a8, a11}是一个最大兼容活动子集,另一个最大子集是{a2, a4, a9, a11}
活动选择问题的最优子结构
于是接下来可以设计一个带备忘机制的递归算法,或者使用自底向上法填写表项。但我们可能忽略了活动选择问题的另一个重要性质,而这一性质可以极大地提高问题求解速度。
贪心选择
假如我们无需求解所有子问题就可以选择出一个子问题加入最优解,我们就可以省去递归式中固有的考察所有选择的过程。
对于活动选择问题,什么是贪心策略?直观上,我们应该选择这样一个活动,选出他后,剩下的资源能被尽量多的其他任务所用。现在考虑可选的活动,其中必然有一个最先结束。因此,直觉告诉我们,应该选择S中最早结束的活动,因为它剩下的资源可供它之后尽量多的活动使用。换句话说,由于活动时间已经按照结束时间单调递增的顺序排序,贪心选择就是活动a1。
做出贪心选择后,只剩下一个子问题需要我们求解:寻找在a1结束后开始的活动
定理:考虑任意非空子问题Sk,令am是Sk中结束时间最早的活动,则am在Sk的某个最大兼容活动子集中。