贪心算法(Greedy Algorithm)之活动选择问题(Activity-Selection Problem)
2009-03-18 13:39
387 查看
活动选择问题是《算法导论》里面关于贪心算法的第一个问题。这个问题是这样的。我们有一组活动,每个活动都有一个开始时间Si和结束时间Fi。如下图:
![](http://p.blog.csdn.net/images/p_blog_csdn_net/hhygcy/EntryImages/20090318/greedy_1_1.png)
每个活动都共享同一个公共的资源(比如教室等)所以同一时间只能有一个活动。现在的问题就是要在指定的时间内让举办的活动数量做大。
这个问题是贪心算法一个典型的应用。说到贪心,贪心基本解决问题的方案就是
#1.尽可能在局部找到一个最优的解
#2然后证明这个局部的优化解是全局优化解的一部分
#3最后把这个局部解用递归或者迭代的方式推广到全局。
所谓贪心,一般都会把带选择的资源做个权重的排序,每次的最优化子结构的选取其实就是最大权重的选取。就这个活动选择问题而言,我们将所有的活动结束时间排序。这里的局部最优解就是指到特定的时间Fi为止的最优解。这个最优解的贪心意义体现在每次最优解利用了最早结束时间,从而是剩余时间最大化。
以上的activity_selector函数就是这样的一个迭代的解。在迭代的过程中,每次都保留一个最近选择活动的index,或者说最近活动的结束时间。用来给后面的活动做比较。(这里的函数实现的不是很妥当,我加入了一些debug信息什么的。)
需要注意的事情是,这个算法非常高效。仅用O(n)的时间就可以找到解决方案。如果动态规划的话。下面就是他的递归式:
![](http://p.blog.csdn.net/images/p_blog_csdn_net/hhygcy/EntryImages/20090318/greedy_1_2.png)
简单地说就是从活动i到j的选择策略就是i-k和k-j的最大策略加1。这个表达式不由让我们想起了矩阵链乘的O(n^3)复杂度.
![](http://p.blog.csdn.net/images/p_blog_csdn_net/hhygcy/EntryImages/20090318/greedy_1_1.png)
每个活动都共享同一个公共的资源(比如教室等)所以同一时间只能有一个活动。现在的问题就是要在指定的时间内让举办的活动数量做大。
这个问题是贪心算法一个典型的应用。说到贪心,贪心基本解决问题的方案就是
#1.尽可能在局部找到一个最优的解
#2然后证明这个局部的优化解是全局优化解的一部分
#3最后把这个局部解用递归或者迭代的方式推广到全局。
所谓贪心,一般都会把带选择的资源做个权重的排序,每次的最优化子结构的选取其实就是最大权重的选取。就这个活动选择问题而言,我们将所有的活动结束时间排序。这里的局部最优解就是指到特定的时间Fi为止的最优解。这个最优解的贪心意义体现在每次最优解利用了最早结束时间,从而是剩余时间最大化。
// Activity_Selection.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <vector> #include <functional> #include <algorithm> #include <iostream> struct activity { int s; int f; }; struct activitySort: public std::binary_function <activity, activity, bool> { bool operator()(const activity& a1, const activity& a2) { return a1.f < a2.f ; } }; struct activityPrint { void operator() (activity a) { std::cout<< "s = "<<a.s <<" , f = "<<a.f <<std::endl;; } }; /** * Description: find the max activity count in a particular time * and print the result *@param a, un-sorted activity set; */ void activity_selector( const std::vector<activity>& av) { std::vector<activity> A; // create one copy since the parameter is const std::vector<activity> a(av); std::sort( a.begin(), a.end(), activitySort() ); A.push_back(a[0]); int j= 0; for (int i=1;i<a.size();i++) { if ( a[i].s >= a[j].f ) { A.push_back(a[i]); j = i; } } std::for_each(A.begin(), A.end(), activityPrint()); } int _tmain(int argc, _TCHAR* argv[]) { // Activity k[] = { {1,4}, {3,5}, {0,6}, {5,7}, {3,8}, {5,9}, {6,10}, {8,11}, {8,12}, {2,11}, {12, 14} }; // un-sorted activity k[] = { {0,6}, {1,4}, {2,11}, {3,5}, {3,8}, {5,7}, {5,9}, {6,10}, {8,11}, {8,12}, {12, 14} }; std::vector<activity> av ( k, k + sizeof(k)/sizeof(k[0]) ); activity_selector(av); system("pause"); return 0; }
以上的activity_selector函数就是这样的一个迭代的解。在迭代的过程中,每次都保留一个最近选择活动的index,或者说最近活动的结束时间。用来给后面的活动做比较。(这里的函数实现的不是很妥当,我加入了一些debug信息什么的。)
需要注意的事情是,这个算法非常高效。仅用O(n)的时间就可以找到解决方案。如果动态规划的话。下面就是他的递归式:
![](http://p.blog.csdn.net/images/p_blog_csdn_net/hhygcy/EntryImages/20090318/greedy_1_2.png)
简单地说就是从活动i到j的选择策略就是i-k和k-j的最大策略加1。这个表达式不由让我们想起了矩阵链乘的O(n^3)复杂度.
相关文章推荐
- 算法导论--贪心算法与动态规划(活动选择问题)
- 第十六章 贪心算法——活动选择问题
- 贪心算法基本概念与活动选择问题的求解
- 算法导论程序40--贪心算法(活动选择问题)
- 贪心算法—活动选择问题
- 贪心算法_活动选择问题
- 贪心算法与活动选择问题 C++实现
- 《算法导论》读书笔记之第16章 贪心算法—活动选择问题
- 贪心算法活动选择问题
- 贪心算法-活动选择问题
- 算法导论 第16章 活动选择问题的递归和迭代贪心算法
- 活动选择问题(活动安排问题)(最大数目活动选择问题)贪心算法C++实现
- 活动选择问题(活动安排问题)(最大数目活动选择问题)贪心算法C++实现
- 活动选择问题(动态规划和贪心算法)
- 贪心算法与活动选择问题和背包问题
- 《算法导论》之 贪心算法—活动选择问题
- 动态规划——贪心算法——活动选择问题 收藏
- 活动选择与小船过河问题(贪心算法)
- 算法导论,贪心算法 —— 活动选择问题(python示例)
- 贪心算法之活动选择问题