首页 > 代码库 > [Wikioi 2913][BZOJ 1029][JSOI 2007]建筑抢修

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

题目描述 Description

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

输入描述 Input Description

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

输出描述 Output Description

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

样例输入 Sample Input

4
100 200
200 1300
1000 1250
2000 3200

样例输出 Sample Output

3

数据范围及提示 Data Size & Hint

 N<150000,t<=15000

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

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

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

#include <stdio.h>#include <algorithm>#include <queue>#define MAXN 170000using 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;}