算法导论学习笔记(七):贪心算法

转载请注明原作者 @yoshino,强烈要求支持TOC目录和数学公式的输入!
更新不及时,有空慢慢写吧,原文是写在Bear上粘贴来的,可能格式有点乱。
具体的工程在我的github上。


贪心算法(greedy algorithm)在每一步都做出当时看起来最佳的选择,通过做局部最优的选择,寄希望这样的选择能导致全局最优解。
贪心算法并不能保证一定能得到最优解,但是对于很多问题确实可以的到最优解。
贪心算法设计过程包含如下:

  1. 确定问题的最优子结构
  2. 设计一个递归算法
  3. 证明我们做出一个贪心选择,那么剩下一个规模更小的子问题
  4. 证明贪心选择总是安全的
  5. 设计一个递归算法实现贪心策略
  6. 将递归算法转换为迭代算法

活动选择问题

问题描述

算法导论学习笔记(七):贪心算法_第1张图片
活动安排问题

问题分析

假设S[i,j]表示在a[i]结束之后及a[j]开始之前这段时间内兼容的活动集合,假设我们希望求S[i,j]的最大相互兼容活动子集A[i,j],包含活动a[k]。
我们得到了两个子问题:

寻找S[i,k]中的兼容活动
寻找S[k,j]中的兼容活动

根据动态规划的知识,用c[i,j]表示S[i,j]的最优解大小,递归可得:
c[i,j]=c[i,k]+c[k,j]+1(+1是因为以a[k]为分隔,最后必须把a[k]算进去)

贪心选择算法

从常识来判断,一般来说的贪心选择都是选择最早结束的活动,从而能够把更多的时间留出来给剩下的活动,故所有与a[1]兼容的活动都要从a[1]结束开始。

   public void greedySelector(int[] s, int[] f) {
        int N = s.length;//为了配合算法,下标都是从1开始
        int[] A = new int[N];
        int j = 1;
        A[j] = 1;//记录最近加入A的活动j
        for (int i = 2; i < N; i++) {
            if (s[i] >= f[j]) {//可以兼容
                A[i] = 1;
                j = i;//下一个活动
            } else {
                A[i] = 0;
            }
        }
        for (int i = 1; i < N; i++) {
            if (A[i] == 1) {
                System.out.print(i + " ");
            }
        }
    }

你可能感兴趣的:(算法导论学习笔记(七):贪心算法)