1、0021算法笔记 【贪心算法】贪心算法与活动安排问题1、贪心算法(1)原理: 在对问题求解时,总是做出在 当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解 。 贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题他能产生整体最优解或者是整体最优解的近似解。(2)特性:贪心算法采用 自顶向下 ,以迭代的方法做出相继的贪心选择,每做一次贪心选择就将所求问题简化为一个规模更小的子问题,通过每一步贪心选择,可得到问题的一个最优解,虽然每一步上都要保证能获得局部最优解,但由此产生的全局解有时不一定是最优的,所以贪婪法不要回溯。能够用贪心算法求
2、解的问题一般具有两个重要特性:贪心选择性质 和 最优子结构性质 。1)贪心选择性质所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素。贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解。证明的大致过程为:首先考察问题的一个整体最优解,并证明可修改这个最优解,使其以贪心选择开始。做了贪心选择后,原问题简化为规模更小的类似子问题。然后用数学归纳法证明通过每一步做
3、贪心选择,最终可得到问题的整体最优解。其中,证明贪心选择后的问题简化为规模更小的类似子问题的关键在于利用该问题的 最优子结构性质 。2)最优子结构性质当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。(3)贪心算法与动态规划算法的差异 :动态规划和贪心算法都是一种递推算法,均有最优子结构性质,通过局部最优解来推导全局最优解。两者之间的区别在于: 贪心算法中作出的每步贪心决策都无法改变,因为贪心策略是由上一步的最优解推导下一步的最优解,而上一部之前的最优解则不作保留,贪心算法每一步的最优解一定包含上一步的最优解。动态规划算法中全局最优解中一定包含某个局部最优解,但不一定包含前
4、一个局部最优解,因此需要记录之前的所有最优解。(4)基本思路:1)建立数学模型来描述问题。2)把求解的问题分成若干个子问题。3)对每一子问题求解,得到子问题的局部最优解。4)把子问题的解局部最优解合成原来解问题的一个解。2、活动安排问题活动安排问题就是要在所给的活动集合中选出最大的相容活动子集合,是可以用贪心算法有效求解的很好例子。该问题要求高效地安排一系列争用某一公共资源的活动。贪心算法提供了一个简单、漂亮的方法使得尽可能多的活动能兼容地使用公共资源。问题描述 :设有 n 个活动的集合 E=1,2,n,其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。每
5、个活动 i 都有一个要求使用该资源的起始时间 si 和一个结束时间 fi,且 si 4. using namespace std; 5. 6. template 7. void GreedySelector(int n, Type s, Type f, bool A); 8. 9. const int N = 11; 10. 11. int main() 12. 13. /下标从 1 开始,存储活动开始时间 14. int s = 0,1,3,0,5,3,5,6,8,8,2,12; 15. 16. /下标从 1 开始,存储活动结束时间 17. int f = 0,4,5,6,7,8,9,10,
6、11,12,13,14; 18. 19. bool AN+1; 20. 21. cout 39. void GreedySelector(int n, Type s, Type f, bool A) 40. 41. A1=true; 42. int j=1;/记录最近一次加入 A 中的活动 43. 44. for (int i=2;i=fj) 47. 48. Ai=true; 49. j=i; 50. 51. else 52. 53. Ai=false; 54. 55. 56. 由于输入的活动以其完成时间的非减序排列,所以算法greedySelector 每次总是选择 具有最早完成时间 的相容
7、活动加入集合 A 中。直观上,按这种方法选择相容活动 为未安排活动留下尽可能多的时间 。也就是说,该算法的贪心选择的意义是 使剩余的可安排时间段极大化,以便安排尽可能多的相容活动 。算法 greedySelector 的效率极高。当输入的活动已按结束时间的非减序排列,算法只需 O(n)的时间安排 n 个活动,使最多的活动能相容地使用公共资源。如果所给出的活动未按非减序排列,可以用 O(nlogn)的时间重排。 例:设待安排的 11 个活动的开始时间和结束时间按结束时间的非减序排列如下:算法 greedySelector 的计算过程如下图所示。图中每行相应于算法的一次迭代。阴影长条表示的活动是已
8、选入集合 A 的活动,而空白长条表示的活动是当前正在检查相容性的活动。若被检查的活动 i 的开始时间 Si 小于最近选择的活动 j 的结束时间fi,则不选择活动 i,否则选择活动 i 加入集合 A 中。贪心算法并不总能求得问题的整体最优解。但对于活动安排问题,贪心算法greedySelector 却总能求得的整体最优解,即它最终所确定的相容活动集合 A 的规模最大。这个结论可以用数学归纳法证明。证明如下:设 E=0,1,2 ,n-1为所给的活动集合。由于E 中活动安排安结束时间的非减序排列,所以活动 0 具有最早完成时间。首先证明活动安排问题有一个最优解以贪心选择开始,即该最优解中包含活动 0.设 a 是所给的活动安排问题的一个最优解,且 a 中活动也按结束时间非减序排列,a 中的第一个活动是活动 k。如 k=0,则a 就是一个以贪心选择开始的最优解。若 k0,则我们设 b=a-k0 。由于 end0 endk,且 a 中活动是互为相容的,故 b 中的活动也是互为相容的。又由于 b 中的活动个数与 a 中活动个数相同,且a 是最优的,故 b 也是最优的。也就是说 b 是一个以贪心选择活动 0开始的最优活动安排。因此,证明了总存在一个以贪心选择开始的最优活动安排方案,也就是算法具有贪心选择性质。程序运行结果如下: