AlvinZH的学霸养成记II
时间限制: 1000 ms 内存限制: 65536 kb
总通过人数: 63 总提交人数: 91
题目描述
由于校赛签到题而迟到的养成记II,你注意到了吗?
AlvinZH妄图成为一个学霸,他想学很多很多的课。
教务网上的课都太固定了,AlvinZH准备去慕课上选几门课学习提高一下姿势。每门课程依然有持续时间 d ,虽然没有固定开始时间,却有结课时间 e ,过了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
猜到是贪心了,然而贪法出错了,一开始想的是时间方向倒着贪心,每次取本时间点结束的,且起点最晚的课,再把时间指针跳到这个起点,过程中不断把备选的课程加入按持续时间的小根堆。这样会出现一个问题,就是每次选走了起点最晚的课,但是这对于剩下的备选的课来说可能造成更坏的情况。
一组数据,我的答案是2,而正确答案显然是3,我一开始会选取15 1,把时间指针跳到14,然而剩余的课程持续的时间就很长,造成错误。
3
7 16
1 15
9 20
正确的贪心是:根据截止时间从小到大排序,用优先队列记录当下已选课程,枚举看看能不能上这门课,如果能就加上这个时间,否则,优先队列里弹出一个占用时间最大值,这样就能满足课程数最大而当下时间最小了。
这么做正确的原因是,如果存在一种方案,那么把方案中的课程重新按照截止时间从小到大的顺序上,一定也是符合条件的(可以用归纳法证明,从两门课入手)
贪心还是需要多练习啊多练习
#include<cstdio>
#include<queue>
#include<algorithm>
#define e first
#define d second
using namespace std;
int n,cur,ans;
pair<int,int> a[100005];
priority_queue<int> Q;
int main()
{
while(scanf("%d",&n)==1)
{
for(int i=1;i<=n;i++)
scanf("%d%d",&a[i].d,&a[i].e);
sort(a+1,a+n+1);
cur=ans=0;
for(int i=1;i<=n;i++)
{
++ans;
Q.push(a[i].d);
cur+=a[i].d;
if(cur>a[i].e)
{
--ans;
cur-=Q.top();
Q.pop();
}
}
while(!Q.empty())
Q.pop();
printf("%d\n",ans);
}
return 0;
}