【贪心+堆】bzoj 1029 抢修建筑(转载+自行理解)
题目描述
小刚在玩JSOI提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者。但是T部落的基地里已经有N个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建筑设施将会完全 毁坏。
现在的情况是:T部落基地里只有一个修理工人,虽然他能瞬间到达任何一个建筑,但是修复每个建筑都需要一定的时间。同时,修理工人修理完一个建筑才能修理下一个建筑,不能同时修理多个建筑。
如果某个建筑在一段时间之内没有完全修理完毕,这个建筑就报废了。你的任务是帮小刚合理的制订一个修理顺序,以抢修尽可能多的建筑。
输入描述:
第一行是一个整数N接下来N行每行两个整数T1,T2描述一个建筑:修理这个建筑需要T1秒,如果在T2秒之内还没有修理完成,这个建筑就报废了。
输出描述:
输出一个整数S,表示最多可以抢修S个建筑.
N < 150,000; T1 < T2 < maxlongint
——————————————————以下为引用————————————————————
原文:https://blog.csdn.net/lyfsb/article/details/70229306
今天的时间好少啊,晚自修还要去听专题报告,都没有时间刷题了,只有打一道水题练练手了。
这题的解题思路是贪心,对每个节点的T2进行排序,然后从小到大修最多的建筑就行了。
但是这个贪心的思路是有问题的:如果T2最小的节点i的T1很大,但是在i的T2范围内有许多节点的T1很小,不就GG了?
所以我们可以用一个堆来维护当前维修的所有建筑的T1,然后枚举下一个节点,若这个节点可以直接维修就修,若不能就判断这个节点的T1值是否比当前的堆顶小,若比堆顶小,就用当前的节点来替换堆顶的节点,也就是为之后的节点空出更多的时间。
因为博主比较懒,所以就打了一个priority_queue,这样比较节省代码。
——————————————————以上为引用————————————————————
附上AC代码:
按死亡时间从小到大排序,如果还有时间,就插入,同时时间减少;
如果不能,那么如果队列里有比它还要慢的任务,就把那个任务踢掉,把这个任务加入。
堆顶是花费时间最多的,堆里的数据就是参与修复的具体房间。
#include <cstdio>
#include <algorithm>
#include <queue>
#include <iostream>
using namespace std;
struct note{
int w,t;
bool operator < (const note lyf) const {//此处用于下面的sort排序
return t<lyf.t;
}
}a[150010];
priority_queue <int> que;//此处为优先队列,默认为大顶堆
int n,now,ans;
int main(void){
cin>>n;
for (int i=1; i<=n; ++i)
cin>>a[i].w>>a[i].t;
sort(a+1,a+1+n);//排序开始的地址要注意;
for (int i=1; i<=n; ++i)
if (now+a[i].w<=a[i].t) //能放入就放入,后面再进行优化,把时间多的丢出来
{
now+=a[i].w;
++ans;
que.push(a[i].w);
}
else if (!que.empty()&&a[i].w<que.top())
{
now+=a[i].w-que.top();
que.pop();
que.push(a[i].w);
}
//如果发现时间有比堆顶还要少的,且堆不为空,把堆顶的置换掉,同时更新目前所花时间。
cout<<ans<<endl;
return 0;
}