【算法】贪心算法

一.前言

二.原理

三.更多例子

 

一.前言

贪心算法(greedy algorithm)在几个基本算法里面算是相对简单的算法了,思路也是非常简单的,每一步总是做出在当前看来最好的选择。也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择,以此希望这样的选择能够产生全局的最优解。对于许多最优化问题,使用动态规划算法来求解最优解有些杀鸡用牛了,可以使用更加简单的算法。动态规划总是在追求全局最优的解,但是有时候,这样有点费时。贪心算法,在求解过程中,并不追求全局最优解,而是追求每一步的最优,所以贪心算法也不保证一定能够获得全局最优解,但是贪心算法在很多问题却额可以求得最优解。贪婪算法所得到的结果往往不是最优的结果(有时候会是最优解),但是都是相对近似(接近)最优解的结果。实际上,贪心算法适用的情况很少。一般,对一个问题分析是否适用于贪心算法,可以先选择该问题下的几个实际数据进行分析,就可做出判断。

贪心算法每一步必须满足一下条件:

  1、可行的:即它必须满足问题的约束。

  2、局部最优:他是当前步骤中所有可行选择中最佳的局部选择。

  3、不可取消:即选择一旦做出,在算法的后面步骤就不可改变了。

贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关,所以对所采用的贪心策略一定要仔细分析其是否满足无后效性基本思路就是从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。当达到某算法中的某一步不能再继续前进时,算法停止。

    1.建立数学模型来描述问题。

    2.把求解的问题分成若干个子问题。

    3.对每一子问题求解,得到子问题的局部最优解。

    4.把子问题的解局部最优解合成原来解问题的一个解。

贪心算法存在的问题是:

1. 不能保证求得的最后解是最佳的; 
2. 不能用来求最大或最小解问题; 
3. 只能求满足某些约束条件的可行解的范围

上述的这些问题可以在动态规划, 回溯算法 ,分支界限算法 里面得到相应的解决,但是我们也不会因此放弃对贪心算法的使用。这正是敏捷开发所提倡的,永远没有最好的,只有最适合的.我们选用贪心算法的原因就是因为他能够满足当前的需要并且比其他算法更加简单。

二.原理

贪心算法可以由如下几个步骤来实现:

  1. 确定问题的最优子结构;
  2. 设计一个递归算法;
  3. 证明如果我们做出一个贪心选择,则只剩下一个子问题;
  4. 证明贪心选择是安全的;
  5. 设计并实现贪心算法。

【算法】贪心算法_第1张图片贪心算法的实现框架:

    从问题的某一初始解出发;

    while (能朝给定总目标前进一步)

    { 

          利用可行的决策,求出可行解的一个解元素;

    }

    由所有解元素组合成问题的一个可行解;

对比动态规划,我们发现贪心算法和它十分相似,首先它们都必须具备最优子结构性质,然后通常都是将原问题分解为子问题,根据最优子结构性质与问题的分解,设计一个递归算法。不同之处在于,动态规划算法在对问题进行分解时,由于无法确定哪一种分解能够得到原问题的最优解,因此需要考察所有的分解情况,并且正是由于这种分解问题的不确定性,通常会导致子问题重叠,为了提高效率,通常会用一个“备忘录”去备忘子问题的解;而在贪心算法中,我们很明确的知道如何分解问题能产生最优解(或者说是很明确的知道哪种选择的结果在最优解中),因此通常贪心算法没有子问题重叠重叠问题,但我们必须要确保贪心选择的正确性。因为用贪心算法只能通过解局部最优解的策略来达到全局最优解,因此,一定要注意判断问题是否适合采用贪心算法策略,找到的解是否一定是问题的最优解。

和动态规划一样,我们也总结出贪心算法的两个特点(必要条件)。

1. 最优子结构性质

当一个问题的最优解包含其子问题的最优解时,称此问题具有 最优子结构性质,问题的最优子结构性质是该问题可以用动态规划或者贪心算法求解的关键特征。

2. 贪心选择性质

其指全局最优解可以通过局部最优解来得到(这也是和动态规划的主要区别),动态规划的算法通常以自底向上的方式来解各种子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每一次的贪心选择就将所求问题简化为规模更小的子问题。

三.更多例子

1.活动选择问题

这是《算法导论》上的例子,也是一个非常经典的问题。有n个需要在同一天使用同一个教室的活动a1,a2,…,an,教室同一时刻只能由一个活动使用。每个活动ai都有一个开始时间si和结束时间fi 。一旦被选择后,活动ai就占据半开时间区间[si,fi)。如果[si,fi]和[sj,fj]互不重叠,ai和aj两个活动就可以被安排在这一天。该问题就是要安排这些活动使得尽量多的活动能不冲突的举行。例如下图所示的活动集合S,其中各项活动按照结束时间单调递增排序。【算法】贪心算法_第2张图片

用贪心法的话思想很简单:活动越早结束,剩余的时间是不是越多?那我就早最早结束的那个活动,找到后在剩下的活动中再找最早结束的不就得了?虽然贪心算法的思想简单,但是贪心法不保证能得到问题的最优解,如果得不到最优解,那就不是我们想要的东西了,所以我们现在要证明的是在这个问题中,用贪心法能得到最优解。【算法】贪心算法_第3张图片

2.钱币找零问题

这个问题在我们的日常生活中就更加普遍了。假设1元、2元、5元、10元、20元、50元、100元的纸币分别有c0, c1, c2, c3, c4, c5, c6张。现在要用这些钱来支付K元,至少要用多少张纸币?用贪心算法的思想,很显然,每一步尽可能用面值大的纸币即可。在日常生活中我们自然而然也是这么做的。在程序中已经事先将Value按照从小到大的顺序排好。

3.背包问题

有一个背包,容量为35磅 , 现有如下物品【算法】贪心算法_第4张图片

  

要求达到的目标为装入的背包的总价值最大,并且重量不超出。

方便计算所以只有3个物品,实际情况可能是成千上万。

同上使用贪婪算法,因为要总价值最大,所以每次每次都装入最贵的,然后在装入下一个最贵的,选择结果如下:

选择: 音响 + 笔,总价值 3000 + 200 = 3200

并不是最优解: 吉他 + 笔记本电脑, 总价值 1500 + 2000 = 3500

当然选择策略有时候并不是很固定,可能是如下:

(1)每次挑选价值最大的,并且最终重量不超出:

选择: 音响 + 笔,总价值 3000 + 200 = 3200

(2)每次挑选重量最大的,并且最终重量不超出(可能如果要求装入最大的重量才会优先考虑):

选择: 音响 + 笔,总价值 3000 + 200 = 3200

(3)每次挑选单位价值最大的(价格/重量),并且最终重量不超出:

选择: 笔+ 显示器,总价值 200 + 2999 = 3199

如上最终的结果并不是最优解,在这个案例中贪婪算法并无法得出最优解,只能得到近似最优解,也算是该算法的局限性之一。该类问题中需要得到最优解的话可以采取动态规划算法。

4.Dijkstra算法,最短路径问题

5.教室调度问题。

6.最小延迟问题。

     

    

你可能感兴趣的:(算法)