题目是P630课程表 III
由于我们不能同时选择两门课程,因此选课需要步步是最优解,我们考虑两个课程[
t
1
t_1
t1,
d
1
d_1
d1]和[
t
2
t_2
t2,
d
2
d_2
d2]。不妨令
d
1
d_1
d1≤
d
2
d_2
d2,我们可以得到结论:先学习结束时间小的(
d
1
d_1
d1),总是最优的。可以证明如下:
假设当前时刻为x,则若先选择一号课程,再选择二号课程,有:
t 1 t_1 t1+ x x x≤ d 1 d_1 d1
t 2 t_2 t2+ t 1 t_1 t1+ x x x≤ d 2 d_2 d2
若先选择二号课程,再选择一号课程有:
t 2 t_2 t2+ x x x≤ d 2 d_2 d2
t 2 t_2 t2+ t 1 t_1 t1+ x x x≤ d 1 d_1 d1
因为 d 1 d_1 d1≤ d 2 d_2 d2,因此我们总有:
t 2 t_2 t2+ t 1 t_1 t1+ x x x≤ d 1 d_1 d1=> t 2 t_2 t2+ t 1 t_1 t1+ x x x≤ d 2 d_2 d2且 t 1 t_1 t1+ x x x≤ d 1 d_1 d1,即:
先选择结束时间长的,若能满足条件,那么一定能先选择时间短的,反之则不然。
因此我们将数组从小到大排序,然后从头遍历,对于遍历过程中,我们还需考虑一种情况:
假如有三个课程分别为[[4,6],[5,5],[2,6]]
排序之后变为[[5,5],[4,6],[2,6]]
假如我们选择一号课程,那么后续课程因为超出截至时间我们都不能选择,此时我们再考虑用贪心算法,对于我们将要选择的课程,如果能选择我们直接选择,如果不能选择并且他的上课时间比我们选择的课程中的最大上课时间小的话,我们就将我们选择的课程中的具有最大上课时间的课程和此时将要选的课程互换。这样的结果一定是最优解,证明略。
因此我们需要一种能储存最大上课时间的数据结构:优先队列。优先队列默认是最大的在堆顶,因此我们可以直接使用。代码如下:
static bool cmp(vector<int>&a,vector<int>&b){
return a[1]<b[1];
}
int scheduleCourse(vector<vector<int>>& courses) {
sort(courses.begin(),courses.end(),cmp);
priority_queue<int>q;
int total=0; //记录选择的课程的总时间
int n=courses.size();
int t,d;
for(int i=0;i<n;i++){
t=courses[i][0];
d=courses[i][1];
if(t+total<=d){ //能选课就直接选择
total+=t;
q.push(t);
}
else if(!q.empty()&&q.top()>t){ //不能选课但比已经选课中的最大时间要小,替换
total-=q.top()-t;
q.pop();
q.push(t);
}
}
return q.size(); //返回优先队列中的数量即可
}