贪心算法

贪心


贪心算法就是遵循某种规则,不断贪心地选取当前最有策略的算法设计方法。不从整体最优上加以考虑,它所做出的仅仅是在某种意义上的局部最优解

​ 贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性。所以,对所采用的贪心策略一定要仔细分析其是否满足无后效性。

无后效性:某个状态以前的过程不会影响以后的状态,只与当前状态有关。

基本思路

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

存在的问题

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

区间调度问题

​ 有n项工作,没项工作分别在 si 时间开始,在 ti 时间结束。每一项工作,均可以选择参与与否。如果选择参与,必须全程参与。此外工作的时间段不能重叠(开始和结束的瞬间重叠也不允许)。

图1

目标是完成尽可能多的工作,那么最多可以参与多少项工作呢?

限制条件

  • 1<=N<=100000
  • 1<=si<=ti<=109

输入

n=5,s={1,2,4,6,8},t={3,5,7,9,10}

输出

3

这个问题可以设计出好几种贪心算法:

  1. 每次选取开始时间最早的工作
  2. 每次选取结束时间最早的工作
  3. 每次选取用时最短的工作
  4. 每次选取与最少工作重叠的工作

其中“每次选取结束时间最早的工作”是正确的,其他的均有反例。

图2

上图为算法1的反例

图3

上图为算法3的反例

图4

上图为算法4的反例

public class Test {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    List<Work> list = new ArrayList<Work>();
    for (int i = 0; i < n; i++) {
      Work work = new Work();
      work.setStart(sc.nextInt());
      work.setEnd(sc.nextInt());
      list.add(work);
    }
    Collections.sort(list);//按照结束时间升序排序
    int count = 1;
    Work tmp = list.get(0);
    for (int i = 1; i < list.size(); i++) {
      if (tmp.getEnd() < list.get(i).getStart()) {
        count++;
      }
    }
    System.out.println(count);
  }

  static class Work implements Comparable<Work> {
    private int start;//开始时间
    private int end;//结束
    public int getEnd() {
      return end;
    }
    public int getStart() {
      return start;
    }
    public void setEnd(int end) {
      this.end = end;
    }
    public void setStart(int start) {
      this.start = start;
    }
    @Override
    public int compareTo(Work work) {
      return this.getEnd() - work.getEnd();
    }
  }
}

例子

POJ 1065.
POJ 1382.
POJ 2586.
POJ 3069.
POJ 3253.
POJ 3617.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值