贪心算法(Greedy)——算法三十六计之四

Posted 信息安全club

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了贪心算法(Greedy)——算法三十六计之四相关的知识,希望对你有一定的参考价值。

 人心不足蛇吞象,世事临头螂扑蝉。——明·罗洪先


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

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

 


01

理论


贪心算法的基本思路:

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

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

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

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


贪心算法的实现框架

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

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

    { 

          利用可行的决策,求出可行解的一个解元素(子问题解);

    }

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


贪心策略适用的前提是:局部最优策略能导致产生全局最优解。所以,贪心算法适用的情况很少。要确定一个问题是否适用于贪心算法,可以先用几个实际数据进行分析并出判断。贪心算法只能通过求局部最优解的策略来达到全局最优解,因此,一定要注意是否适合采用贪心算法策略,找到的解是否一定是问题的最优解。


02


实践


[背包问题]有一个背包,背包容量是M=150。有7个物品,物品可以分割成任意大小。要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。


物品 (o)    A  B  C  D  E  F  G

重量(w)   35 30 60 50 40 10 25

价值(p)    10 40 30 50 35 40 30


分析:

目标函数: ∑pi最大

约束条件是装入的物品总重量不超过背包容量,即∑wi<=M( M=150)


(1)根据贪心的策略,每次挑选价值最大的物品装入背包,得到的结果是否最优?

(2)每次挑选所占重量最小的物品装入是否能得到最优解?

(3)每次选取单位重量价值最大的物品,成为解本题的策略?


贪心算法是很常见的算法之一,这是由于它简单易行,构造贪心策略简单。但是,它需要证明后才能真正运用到题目的算法中。一般来说,贪心算法的证明围绕着整个问题的最优解一定由在贪心策略中存在的子问题的最优解得来的。对于本例题中的3种贪心策略,都无法成立,即无法被证明,解释如下:


(1)贪心策略:选取价值最大者。反例:

W=30

物品:A  B  C

重量:28 12 12

价值:30 20 20

根据策略,首先选取物品A,接下来就无法再选取了,可选取B、C则更好。


(2)贪心策略:选取重量最小。它的反例与第一种策略的反例差不多。


(3)贪心策略:选取单位重量价值最大的物品。反例:

W=30

物品:A  B  C

重量:28 20 10

价值:28 20 10

根据策略,三种物品单位重量价值一样,程序无法依据现有策略作出判断,如果选择A,则答案错误。


值得注意的是,贪心算法并不是完全不可以使用,贪心策略一旦经过证明成立后,它就是一种高效的算法。比如,求最小生成树的Prim算法和Kruskal算法都是漂亮的贪心算法。


[均分纸牌]有N堆纸牌,编号分别为1,2,…,n。每堆上有若干张,但纸牌总数必为n的倍数.可以在任一堆上取若干张纸牌,然后移动。移牌的规则为:在编号为1上取的纸牌,只能移到编号为2的堆上;在编号为n的堆上取的纸牌,只能移到编号为n-1的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。例如:n=4,4堆纸牌分别为:① 9 ② 8 ③ 17 ④ 6 。移动三次可以达到目的:从③取4张牌放到④ 再从③区3张放到②然后从②去1张放到①。


算法分析:设a[i]为第I堆纸牌的张数(0<=I<=n),v为均分后每堆纸牌的张数,s为最小移动次数。


我们用贪心算法,按照从左到右的顺序移动纸牌。如第I堆的纸牌数不等于平均值,则移动一次(即s加1),分两种情况移动:


1.若a[i]>v,则将a[i]-v张从第I堆移动到第I+1堆;

2.若a[i]<v,则将v-a[i]张从第I+1堆移动到第I堆。


为了设计的方便,我们把这两种情况统一看作是将a[i]-v从第I堆移动到第I+1堆,移动后有a[i]=v; a[I+1]=a[I+1]+a[i]-v.


在从第I+1堆取出纸牌补充第I堆的过程中可能回出现第I+1堆的纸牌小于零的情况。


如n=3,三堆指派数为1 2 27 ,这时v=10,为了使第一堆为10,要从第二堆移9张到第一堆,而第二堆只有2张可以移,这是不是意味着刚才使用贪心法是错误的呢?


我们继续按规则分析移牌过程,从第二堆移出9张到第一堆后,第一堆有10张,第二堆剩下-7张,在从第三堆移动17张到第二堆,刚好三堆纸牌都是10,最后结果是对的,我们在移动过程中,只是改变了移动的顺序,而移动次数不便,因此此题使用贪心法可行的。


Java源程序:

public class Greedy {

    public static void main(String[] args) {

      int n = 0, avg =0, s = 0;

      Scanner scanner = new Scanner(System.in);

      ArrayList<Integer> array = new ArrayList<Integer>();

      System.out.println("Please input the number of heaps:");

      n = scanner.nextInt();

      System.out.println("Please input heap number:");

      for (int i = 0; i < n; i++) {

           array.add(scanner.nextInt());

      }

      for(int i = 0; i < array.size(); i ++){

       avg += array.get(i);

      }

      avg = avg/array.size();

      System.out.println(array.size());

      System.out.println(avg);

      for(int i = 0; i < array.size()-1; i ++){

       s++;

       array.set(i+1, array.get(i+1)+array.get(i)-avg);   

      }

      System.out.println("s:" + s);

     }

}


利用贪心算法解题,需要解决两个问题:一是问题是否适合用贪心法求解。二是确定了可以用贪心算法之后,如何选择一个贪心标准,才能保证得到问题的最优解。在选择贪心标准时,我们要对所选的贪心标准进行验证才能使用,不要被表面上看似正确的贪心标准所迷惑。


贪心算法所作的选择可以依赖于以往所作过的选择,但决不依赖于将来的选择,也不依赖于子问题的解,因此贪心算法与其他算法相比具有一定的速度优势。如果一个问题可以同时用几种方法解决,贪心算法应该是最好的选择之一。


以上是关于贪心算法(Greedy)——算法三十六计之四的主要内容,如果未能解决你的问题,请参考以下文章

单细胞36计之5趁火打劫---锚点整合

「码趣分享」贪心算法Greedy Algorithm

策略模式-三十六计

每周算法贪心算法(Greedy Algorithm)

零基础学启发式算法-贪心算法(Greedy Algorithm)

单细胞36计之1瞒天过海---纠结的细胞分群