贪心算法
1.贪心算法概述
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
找到贪心的启发式表达式并不难,难的是证明贪心是最优解。
援引自另一位大神:有人说贪心算法是最简单的算法,原因很简单:你我其实都很贪,根本不用学就知道怎么贪。有人说贪心算法是最复杂的算法,原因也很简单:这世上会贪的人太多了,那轮到你我的份?
2.贪心算法的基本思路
- 建立数学模型来描述问题。
- 把求解的问题分成若干个子问题。
- 对每一子问题求解,得到子问题的局部最优解。
- 把子问题的解局部最优解合成原来解问题的一个解。
所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别。
因为动态规划算法通常以自底向上的方式递归解各子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。
这里简单明确一下递归和迭代的区别:递归是程序不断调用自身的过程,把复杂问题求解推到到比原问题更简单一些的问题,然后在获得最简单的情况之后逐步返回,依次得到复杂的解;而迭代则是利用原来变量的值来推算一个新的值。递归中一定有迭代(镜子中的镜子),但是迭代中不一定有递归(自动步枪用枪焰制退弹壳装弹)
知乎 -「递归」和「迭代」有哪些区别?
3.贪心算法适用的情况
贪心策略适用的前提是:局部最优策略能导致产生全局最优解。
实际上,贪心算法适用的情况很少。一般,对一个问题分析是否适用于贪心算法,可以先选择该问题下的几个实际数据进行分析,找一下有没有反例就可以判断。
贪心算法的实际应用
1.最小生成树
最小生成树——Prim算法、Kruskal算法和Boruvka算法
2.最短路径Dijkstra算法
3.区间调度问题
输入:一组标有开始时间和结束时间的工作区间。
((s(i),f(i)):i=1,...,n)
输出:最大数量的不互相重叠可以在一个CPU上执行的区间集合。
贪心区间调度等驾驭找到一个图中的最大独立集(Maximum Independent Set),图中的顶点为一区间,如果区间重叠则它们之间有一条边。
解决方法:Earliest Finishing Time(EFT),选择不重叠的,有最早结束时间的区间。
时间复杂度:O(nlogn)
证明:
4.区间划分(区间着色)问题
输入:一组标有开始时间和结束时间的工作区间。$(( s(i), f(i) ):i=1,…,n )
输出:能够并发执行这些工作的服务器的数量。
一台服务器同时只能解决一项工作,一项工作也只能在一台server上运行。这个问题等价于将重叠的工作分配不同的颜色,所需要的颜色种类。
解决方法:将这一组工作按照开始时间排序,当一个新的工作执行时,为它分配目前没有分配的着色数量最少的颜色。
时间复杂度:O(nlogn)
证明:另d表示区间的深度,即最大的重合区间的数量,贪心算法正好使用了d种颜色,而其他算法至少要用d种颜色。
5.最小延迟调度
输入:一组带有处理所需时间(process time)和截止时间(due time)的工作
((p(i),d(i)):i=1,...,n)
输出:在一个处理器上对工作进行调度,计算每个工作的开始时间,使得总延迟最小。
Li=max(0,fi−di)
解决方法:Earliest Deadline First(EDF),选择截止日期最早的工作优先执行。
证明:根据算法定义,EDF是没有空闲时间的,不会出现赶deadline的情况。
我们引入概念inversion,来表示两个工作i、j,在di < dj 的情况下,却有 si < sj。即后due的先执行为inversion。EDF算法不存在inversion,inversion交换解决之后,总Latency不会增大,证明如下:
L = Li + Lj表示交换之前的总latency
L’ = Li’ + Lj’表示交换之后的总latency。
易得,Li’ <= Li,因为工作i执行的更早了;
Lj’ <= Li,因为工作j的due time 更晚。
转自:
http://blog.csdn.net/effective_coder/article/details/8736718
http://www.cnblogs.com/steven_oyj/archive/2010/05/22/1741375.html