1. 问题描述:
有n项工作,每项工作分别在si时间开始,在ti时间结束.
对于每项工作,你都可以选择参与与否.如果选择了参与,那么自始至终都必须全程参与.
此外,参与工作的时间段不能重复(即使是开始的瞬间和结束的瞬间的重叠也是不允许的).
你的目标是参与尽可能多的工作,那么最多能参与多少项工作呢?
1≤n≤100000
1≤si≤ti≤10^9
输入:
第一行:n
第二行:n个整数空格隔开,代表n个工作的开始时间
第三行:n个整数空格隔开,代表n个工作的结束时间
样例输入:
5
1 2 4 6 8
3 5 7 9 10
样例输出:
3
说明:选取工作1,3,5
2. 从题目中的最多的字眼可以知道这道题目考察的是贪心的问题,所以我们可以从贪心的思路来分析问题与解决问题。其中贪心的难点是如何想出一个策略使得在这种策略之下使得问题得到最优的解
对于这道问题我们可以这样想,先看看从时间开始比较早的来看一下是否满足题目的要求,对于这种区间的问题,最好在途中画出图来帮助我们更好地理解这个问题,
可以发现选择时间比较早的确实可以得到题目中的答案,但是这种方案是否为最优呢?我们不妨可以多举出几个例子来证明自己的猜想,在某些情况下,有的开始的时间比较早,但是结束的时间很晚,导致中间覆盖的区间很多,以至于整个区间覆盖过的区间都不能够选择,那么可以知道这种方案并不是最优的
此外我们也可以选择花费时间比较短的区间,但是举出几个例子之后发现也是不行的,因为有的区间虽然花费时间比较短但是它可能覆盖了好几个区间导致覆盖的区间也不能够选择,所以这个方案也不是最优的
还有一种方法是看结束时间,多举出几个例子发现这个方案的确是最优的,结束的时间越早,那么它可以选择的工作就相对来说是比较多的,确定较策略之后那么代码就不是特别难了,其中涉及到的是一些细节的问题
我们需要对所有的结束时间进行排序,然后选择出没有被这个区间覆盖的而且开始时间大于这个区间的结束时间的下一个区间
其中涉及到了排序但是排完序之后原来的开始时间和结束时间有可能会被打乱
这个时候我们就需要使用到Java中的面向对象的思维模式了,Java中的类把所有的属性都绑定在了一起所以我们可以使用在外部类中创建一个私有的内部类,并且加上这个修饰类的修饰符static,假如没有加上static的话那么会导致在调用这个内部类的构造方法的时候会报错,因为涉及到了排序的问题,所以我们需要实现一个接口Comparable,重写其中的CompareTo方法,其中这个方法自定义了比较的规则(假如结束时间相同开始时间较前的排序在前面,结束时间不同那么结束时间短的排序在前面)那么经过排序之后开始时间和结束时间是绑定在一起的,我们在选择的时候选择结束时间较前的,而且选择完整个区间之后需要标记一下选择的哪个区间,方便选择下一个区间的对上一个已经选择好的区间进行判断
3. 具体的代码如下:
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int s[] = new int[n];
int t[] = new int[n];
//创建对象数组方便进行排序
Job job[] = new Job[n];
for(int i = 0; i < n; i++){
s[i] = sc.nextInt();
}
for(int i = 0; i < n; i++){
t[i] = sc.nextInt();
}
for(int i = 0; i < n; i++){
job[i] = new Job(s[i], t[i]);
}
Arrays.sort(job);
/*for(int i = 0; i < n; i++){
System.out.println(job[i].s + " " + job[i].t);
}*/
//标记结束时间
int y = job[0].s;
//使用一个计数变量来进行计数符合条件的工作,count = 1是因为已经有选择了第一个的任务
int count = 1;
for(int i = 1; i < n; i++){
if(job[i].s > y){
count++;
y = job[i].t;
}
}
System.out.println(count);
sc.close();
}
//因为控制台输入的数据并不是有顺序的,所以不能够对单个数组进行排序,这样的话只能对开始时间与结束时间进行绑定一起排序
//需要实现Comparable接口这样才可以对对象进行自定义的排序
//所以这里体现了面向对象的思想
public static class Job implements Comparable<Job>{
private int s;
private int t;
public int getS() {
return s;
}
public int getT() {
return t;
}
public void setT(int t) {
this.t = t;
}
public void setS(int s) {
this.s = s;
}
//构造方法用来对属性进行操作(赋值)
public Job(int s, int t) {
super();
this.s = s;
this.t = t;
}
@Override
public int compareTo(Job obj) {
//对结束时间进行排序
int x = this.getT() - obj.getT();
if(x < 0) return x;
return this.getS() - obj.getS();
}
}
}
总结一下:其中涉及到的一个难点是如何制定最优的策略的问题(猜想加证明),第二个难点是如何将乱序的一组的数据排序之后还是按照原来是一组的方式排列在一起