Case03——区间调度问题
问题描述:
有n项工作,每项工作分别在si开始,ti结束。对每项工作,你都可以选择参加或不参加,但选择了参加某项工作就必须至始至终参加全程参与,即参与工作的时间段不能有重叠(即使开始的时间和结束的时间重叠都不行)。
限制条件:
1<=n<=100000
1<=si<=ti,=109
样例:
输入
n=5
1,2,4,6,8
3,5,7,9,10
输出
3(选择工作1, 3, 5(可选择性输出))
先理一下题目描述的
1 3 是一个区间;
2 5 是一个区间;
4 7是一个区间;
6 9是一个区间;
8 10是一个区间;
我们可以有以下的方法:
1,找结束时间早的;
2,找开始时间早的;
3,每次选取用时最短的;
4,在可选工作中,每次选取与最小可选工作有重叠的部分;
对于贪心我们可以采取举证取反例的方法
我们可以发现找结束时间最早的是最优的方法
但是我们不能保证每一个开始时间集合,结束时间是有序的,这就用到面向对象的知识了,打包在一起,做对象数组。
并重写CompareTo方法,排序结束时间,如果结束时间一样就,排序开始时间最早的时间
代码如下:
package greed_dynamic;
import static java.lang.Math.min;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Pra {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] s = new int[n];
int[] t = new int[n];
//处理输入
for (int i = 0; i < n; i++) {
s[i] = sc.nextInt();
}
for (int i = 0; i < n; i++) {
t[i] = sc.nextInt();
}
//创建对象数组
job[] jobs = new job[n];
for (int i = 0; i < t.length; i++) {
jobs[i] = new job(s[i],t[i]);
}
System.out.println(f(n,jobs));
}
private static int f(int n, job[] jobs) {
// TODO 自动生成的方法存根
int cnt = 1;
//第一个任务必选
int y = jobs[0].t;
for (int i = 0; i < jobs.length; i++) {
//找大于结束时间最早的开始时间,并更新与之对应的结束时间
if (jobs[i].s > y) {
cnt++;
y = jobs[i].t;
}
}
return cnt;
}
public static class job implements Comparable<job>{
int s;
int t;
//构造函数
public job (int s,int t) {
this.s = s;
this.t = t;
}
//重写compareTo方法
public int compareTo(job other) {
// TODO 自动生成的方法存根
int x = this.t - other.t;//对结束时间排序
if (x == 0) {//结束时间一致,排序开始时间
return this.s - other.s;
}
return x;
}
}
}