vlambda博客
学习文章列表

算法详解:【贪心算法】入门


概念

贪心算法,也称贪婪算法。

贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。

贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。

当然,希望贪心算法得到的最终结果也是整体最优的。虽然贪心算法不能对所有问题都得到整体最优解,但对许多问题它能产生整体最优解。在一些情况下,即使贪心算法不能得到整体最优解,但其最终结果却非常接近最优解。


算法思路

贪心算法是一种不追求最优解,只希望得到较为满意解的方法。贪心算法一般可以快速得到满意的解,因为它省去了为找最优解要穷尽所有可能而必须耗费的大量时间。贪心算法常以当前情况为基础作最优选择,而不考虑各种可能的整体情况,所以贪心算法不需要回溯。


算法特点

通过做局部最优(贪心)选择来达到全局最优解。使用贪心算法时,通常采用自顶向下的方法来解,每一步都使用最贪心的选择,使原问题变为一个相似的、规模更小的问题。


基本思路

从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快地求得更好的解。当达到算法中的某一步不能再继续前进时,就停止算法,给出近似解。

由贪心算法的特点和思路可看出,该算法存在以下问题:

  • 不能保证最后的解解还是最优的;

  • 不能用来求最大或最小解问题;

  • 只能求满足某些约束条件的可行解的范围。



算法流程

(1)建立数学模型来描述问题。
(2)把求解的总问题分成若干个子问题。
(3)对每一个子问题求解,得到子问题的局部最优解。
(4)把子问题的局部最优解合成原来总问题的一个解。


伪代码

从问题的某一初始解出发
while (是否达到(或近似达到)设定的总目标) 
    求出可行解的一个解元素;
由所有解元素组合成问题的一个可行解


示例:找零钱

问题描述

收银员为顾客找零时,发现只有100、50、20、10、5、1、0.5、0.1这些面额的人民币(单位:元)。问:如果给顾客77.7元零钱,那如何找零呢?

题目分析

(1)建立数学模型
  设收银员应找零为M元,纸币面额种类有X1、X2...Xn种,每种纸币需要Y1、Y2...Yn张,则有:
X1Y1 + X2Y2 + … + XnYn = M


(2)问题拆分为子问题
  在找零过程中,可以划分为n个子问题:即每个子问题对应为:
在未超过当前应找零数目的前提下,在相应面额的纸币中选择一张纸币。


(3)制定贪心策略,求解子问题

制定的贪心策略为:在一定的条件下,从面额最大的纸币开始选取。则整个求解过程如下:

  • 选取面额为50元的纸币,则 X1 = 50, M = 77.7 - 50 = 27.7元;

  • 选取面额为20的纸币,则 X2 = 20, M = 27.7 - 20 = 7.7

  • 选取面值为5的纸币,则 X3 = 5, M = 7.7 - 5 = 2.7

  • 选取面值为1的纸币,则 X4 = 1, M = 2.7 - 1 = 1.7

  • 继续选取面值为1的纸币,则 X5 = 1, M = 1.7 - 1 = 0.7

  • 选取面值为0.5元的纸币,则 X6 = 0.5, M = 0.7 - 0.5 = 0.2

  • 选取面值为0.1元的纸币,则 X7 = 0.1, M = 0.2 - 0.1 = 0.1

  • 继续选取面值为0.1元的纸币,则 X8 = 0.1, V = 0.1 - 0.1 = 0元;

  • 求解结束

(4)将所有解元素合并为原问题的解

需要找零:50元1张、20元1张、5元1张、1元2张、5角1张,1角2张。

代码实现