一、什么是贪心算法?
贪心算法指对问题求解时,总是做出在当前看来是最好的选择,期望通过所做的局部最后选择来产生出一个全局最优解。
二、贪心算法的适用场景
首先,在利用贪心算法求解问题之前,我们需要清楚什么样的问题适合用贪心算法求解。一般而言,能够利用贪心算法求解的问题都会具备以下两点性质:
- 贪心选择
- 最优子结构。
如果我们能够证明问题具备这两个性质,那么就可以设计出它的一个贪心算法。
2.1 贪心选择性质
一个全局最优解可以通过可以通过局部最优选择来达到。
换句话说,当考虑如何做选择时,我们只考虑对当前问题最佳的选择、而不考虑子问题的结果。
在贪心算法中,我们所做的总是当前看似最佳的选择,然后再解决选择之后所出现的子问题。贪心算法所做的当前选择可能要依赖于已经做出的所有选择,但不依赖于有待于做出的选择或子问题的解。
我们必须证明在每一步所做的贪心选择最终能产生一个全局最优解。
2.2 最优子结构
对于一个问题来说,如果它的一个最优解包含了其子问题的最优解,则称该问题具有最优子结构。
假设在原问题中做了一个贪心选择而得到了一个子问题,真正要做的是证明将此问题的最优解与所做的贪心选择合并后,的确可以得到原问题的一个最优解。这个方案意味着要对子问题采用归纳法,来证明每个步骤中所做的贪心选择最终会产生出一个最优解。
贪心算法与动态规划的不同在于他对每个子问题的解决方案都是局部最优选择,不能回退。
动态规划则会保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能。
如何证明贪心算法的正确性?
以活动选择问题为例, 活动集合S={1,2,..., n}。
现在要证明的是,如果每一步都进行贪心选择,执行到第k步时,选择的k项活动为i1, i2, ..., ik,那么存在一个最优解包含活动i1,i2, ... ik。根据上述命题,对于任何k,算法前k步的选择都将导致最优解,至多到第n步将得到问题实例的最优解。
- 采用归纳法证明:
首先将活动按照结束时间非递减排序,记排序后的结果为S={1,2,...,n}, f1<=f2<=...<=fn。
- 当k = 1时,设最优解为A = {i1, i2, ... , ij}, 如果i1不等于1, 因为活动1结束的时间最早,那么用1替换i1后得到的A'也是问题的一个最优解;
- 假设对于任意的正整数k,命题正确, 即存在一个全局最优解A={i1=1, i2, ..., ik}∪B,其中B为全局最优解A中除了i1, i2,...,ik以外的部分。
记S中除了{i1, i2, ..., ik}剩下部分中与i1, i2, ..., ik相容的活动集合为S', 那么B必然是S'的一个最优解。
反证法证之:
假设B不是S'的最优解,即存在最优解B'的活动比B多, 那么{i1, i2,...,ik}∪B' > {i1,i2,...,ik}∪B, 与A是全局最优解矛盾。
既然B是S'的一个最优解。根据1的结论,S'中结束时间最早的活动(ik+1)总会导致一个最优解,如果B中包含ik+1, 那么就说明最优解A中包含ik+1;
如果B中不包含ik+1, 那么一定存在S'的另外一个最优解B'包含ik+1, 即:
{i1,i2,...,ik}∪B = {i1,i2,...,ik}∪B', 其中B'={ik+1,...}
因此{i1, i2,...,ik, ik+1}一定出现在一个最优解集合中。
命题得证。