AlvinZH的学霸养成记II
时间限制:1000ms 内存限制:65536kb
题目描述
由于校赛签到题而迟到的养成记II,你注意到了吗?
AlvinZH妄图成为一个学霸,他想学很多很多的课。
教务网上的课都太固定了,AlvinZH准备去慕课上选几门课学习提高一下姿势。每门课程依然有持续时间 dd ,虽然没有固定开始时间,却有结课时间 ee ,过了DDL后不可再学习此课程。AlvinZH只有在连续学习完一门课后,才会开始下一门课的学习,AlvinZH必须得在结课之前完成每门课的学习。
AlvinZH想知道他最多能学习多少门课,你来帮帮他吧!
注:AlvinZH最早可以从第一天开始学习,结课时间e代表将在第e天结课。
输入
输入包含多组数据。
每组数据第一行为课程数n(0<n≤10^5)。
接下来n行,每行两个整数d和e,代表课程持续时间和结课DDL(0<d,e≤10^6)。
输出
对于每组数据,输出一行,为AlvinZH最多可学习的课程数。
输入样例
3
1 1
2 2
3 3
输出样例
1
HINT
你想到优先队列了吗?
HINT2
可参考Leetcode 630. Course Schedule III
题目分析
考虑到这里有分别的结束限制,很直观想法是结束时间靠前的先处理。所以,按照DDL排序,按序处理每门课。
这时候考虑,某个结束时间靠前的在某个DDL之前放可能是忧的,但是他可能影响DDL靠后的课程的放置导致之后不优。但是,对于当前处理的DDL,显然放置的科目都是DDL更靠前的。所以删除之前的课并不影响结果。
思考到这步结果就出来了,对于某个课的DDL,假设前一个的最多放置方案用了Tot的时间,当前课需要c,如果Tot+c<=DDL则直接放置,否则选出曾经放置的时间最长的课,对比当前的课:如果当前课的代价小,则删除选出的课,放进当前的课;否则不变。二叉堆维护即可。
具体思路
贪心+优先队列优化
设置st为当前时间
按结束时间e排序,依次选择,并将持续时间d入队,更新st,若st>e则说明无法安排这门课,但此时不是将该门课出队,而是将队列内d最长的课出队(易知能保证出队后st<e,且能使st更小,因此这样做是合理的).
出现的问题:一开始优先队列的类型建的结构体的,觉得逻辑和实现都没问题,但就一直WA。换了一种写法,用int的优先队列就过了。然而两种写法贪心部分的逻辑是一样的,初步判定问题在于sort或优先队列的实现上,最后发现sort时比较的是结构体的e参量,而优先队列中比较的是d参量,wa的代码只用e的关系重载了结构体的<符,增加了cmp后过了
AC代码
1 #include<algorithm> 2 #include<iostream> 3 #include<cstdio> 4 #include<queue> 5 using namespace std; 6 struct Lesson{ 7 int d,e; 8 bool operator < (const Lesson &a) const{ //重载<,l1<l2为真当且仅当l1.e<l2.e,此时优先队列生成最大堆 9 return d<a.d; 10 } 11 }; 12 bool cmp(Lesson l1,Lesson l2){ 13 return l1.e<l2.e; 14 } 15 const int maxn=100007; 16 priority_queue<Lesson> q; 17 Lesson l[maxn]; 18 int main(){ 19 int n; 20 while(~scanf("%d",&n)){ 21 int st=0; 22 for(int i=0;i<n;++i){ 23 scanf("%d%d",&l[i].d,&l[i].e); 24 } 25 sort(l,l+n,cmp); 26 while(!q.empty()) q.pop(); 27 for(int i=0;i<n;++i){ 28 st+=l[i].d; 29 q.push(l[i]); 30 if(st>l[i].e){ 31 st-=q.top().d; 32 q.pop(); 33 } 34 } 35 printf("%d ",q.size()); 36 } 37 }