区间调度问题之最多区间调度详解——贪心解法(对于参考博文的一些补充与注释)

参考博文:https://blog.csdn.net/kiritow/article/details/52208488

题目描述

有N项工作,每项工作分别在Si时间开始,在Ti时间结束。对于每项工作,你都可以选择参与与否。如果选择了参与,那么自始至终都必须全程参与。此外,参与工作的时间段不能重叠(即使是开始的瞬间和结束的瞬间重叠也是不允许的)。

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

样例输入

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

样例输出

3 (选取工作1、3、5)

题目分析

作为一个正常人,我们不太可能一眼就想到用贪心算法来解决这个问题,这里的贪心用法是在多次优化后得出的。

首先想到的一般是得到一个解空间,通过暴力解法得到所有的可能,再逐一的去验证,在符合的方案中找到一个最优的方案。

最优化问题都可以通过某种搜索获得最优解,最多区间调度问题也不例外。该问题无非就是选择几个不重叠的区间而已,看看最多能选择多少个,其解空间为一棵二叉子集树,某个区间选或者不选构成了两个分支,如图四所示。我们的目标就是遍历这棵子集树,然后看从根节点到叶节点的不重叠区间的最大个数为多少。可以看出,该问题的解就是n位二进制的某个0/1组合。子集树共有2^n种组合,每种组合都需要判断是否存在重叠区间,如果不重叠则获得1的个数。

上述的例子一共八种组合:

  1. a
  2. ab
  3. ac
  4. ad
  5. abc
  6. abd
  7. acd
  8. abcd

现在我们已经得到解空间了,在不进行如何优化的前提下暴力求解。此时如果abcd不是有序排列的区间,则每种组合判断是否有重叠区间的复杂度为O(n^2):{为了确保所有的区间都不覆盖,a应与bcd分别比较共3次,b再与cd分别比较共2次,c再与d比较共1次。数学表达即 (n-1)+(n-2)+(n-3)……+1=1/2(n^2-n)==>即每种组合检验是否有重叠区间的复杂度为O(n^2)}

此时该算法的复杂度为2^n*O(n^2),即O(2^n*n^2),是十分不理想的,现在进行第一次优化。

先将所有区间排个序(按开始时间或者结束时间)

这样排完序后,判断区间是否重叠的算法马上就降到O(n)了。

然后让我们进一步思考,我们能不能优化解空间呢?此处我们可以用贪心的解法,每一步都选择最优的,这样就可以把O(2^n)压缩到O(1)。这个方法实在是巧妙,证明不会,就举个反例吧!

如果按开始时间排:

这个策略显然不行,结果只有a一个。

如果按结束时间排:

这个策略可以的,结果为3个。想法为尽可能先选最早结束的,这样才能选到最多的任务。

证明:https://www.cnblogs.com/ordili/p/8495998.html

代码

package POJ.动态规划与贪心算法;

import java.util.Arrays;

public class Section {
	public static void main(String[] args) {
		int count=1;//最多可参与的工作数
		Task[] t=new Task[] {new Task(1, 3),new Task(8,10),
				new Task(4,7),new Task(6,9),new Task(2,5)};
		Arrays.sort(t);
		for(int i=0;i<t.length;++i) {
			System.out.println(t[i]);
		}
		int end=0;
		for(int i=1;i<t.length;++i) {
			if(t[end].et<t[i].st) {
				count+=1;
				end=i;
			}
				
		}
		System.out.println(count);
	}
}
class Task implements Comparable<Task>{

	int st;
	int et;
	
	public Task(int st, int et) {
		super();
		this.st = st;
		this.et = et;
	}

	@Override
	public int compareTo(Task o) {
		return this.et-o.et;
	}
	@Override
		public String toString() {
			return st+","+et;
		}
}

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值