【贪心】Buaacoding1032 AlvinZH的学霸养成记II

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
#include
#include
#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;
}

你可能感兴趣的:(Buaacoding,贪心)