[Wikioi 2913][BZOJ 1029][JSOI 2007]建筑抢修

小刚在玩JSOI提供的一个称之为“建筑抢修”的电脑游戏: 经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者。但是T部落的基地里已经有N个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建筑设施将会完全毁坏。现在的情况是:T部落基地里只有一个修理工人,虽然他能瞬间到达任何一个建筑,但是修复每个建筑都需要一定的时间。同时,修理工人修理完一个建筑才能修理下一个建筑,不能同时修理多个建筑。如果某个建筑在一段时间之内没有完全修理完毕,这个建筑就报废了。你的任务是帮小刚合理的制订一个修理顺序,以抢修尽可能多的建筑。

第一行是一个整数N,接下来N行每行两个整数T1,T2描述一个建筑:修理这个建筑需要T1秒,如果在T2秒之内还没有修理完成,这个建筑就报废了。

输出一个整数S,表示最多可以抢修S个建筑。

4
100 200
200 1300
1000 1250
2000 3200

3

 N<150000,t<=15000

数据不是原数据,是本人自己出的数据。t的范围也与原题不同。

又是一道贪心题,明眼人都能看出来,没想到这个题居然会出现在JSOI省选里,我的代码才三十多行,真爽!不过这个贪心要用个大根堆来维护最优解,先将所有建筑按其消失时间升序排序(越先消失的建筑越要先抢救),用变量nowtime记录当前时间,从第一个到最后一个建筑判断修了它后,是否会超出它的消失时间(这样就抢救不了之后的建筑了),如果是的话,就要在大根堆里找出队首建筑,这个已经修好的建筑是最耗时的,如果队首建筑的维修耗时比这个建筑大,而且如果不修队首建筑的话,还能抢救这个建筑,那么就更新当前时间,去掉(不修)队首建筑,转而将此建筑入队

所有建筑遍历完了后,大根堆中的元素数量就是能抢救回来的最多建筑数了,输出它即可

#include <stdio.h>
#include <algorithm>
#include <queue>
#define MAXN 170000
using namespace std;
struct T
{
	int t1,t2;
	friend bool operator<(T a,T b){return a.t2<b.t2;} //排序用
}a[MAXN];
priority_queue<int>q; //大根堆q保存已经修理的建筑的各自的修理所需时间
int main()
{
	int i,j,n,nowtime=0; //nowtime=当前时间
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		scanf("%d%d",&a[i].t1,&a[i].t2);
	sort(a+1,a+n+1); //按结束时间升序排序
	for(i=1;i<=n;i++)
	{
		if(nowtime+a[i].t1<=a[i].t2) //如果修完第i个建筑后的时间比第i个建筑消失时间早
		{	
			nowtime+=a[i].t1; //当前时间加上第i个建筑所需修理时间
			q.push(a[i].t1); //将第i个建筑所需修理时间入队
		}
		//否则,在第i个建筑消失前不能修好它,那么就需要判断是否需要舍掉之前一个修过的建筑,腾出时间修这个建筑
		else if(nowtime+a[i].t1-q.top()<=a[i].t2&&a[i].t1<=q.top()) //不修之前最费时的建筑后,这个建筑能修好,且建筑i费时比那个建筑少,那个就舍掉那个最费时的建筑
		{
			nowtime=nowtime+a[i].t1-q.top();
			q.pop();
			q.push(a[i].t1);
		}
	}
	printf("%d\n",q.size()); //最终大根堆里的元素数目就是抢救回来的最多建筑数
	return 0;
}

你可能感兴趣的:(数据结构,贪心,二叉堆)