题目描述 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 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; }