【JSOI2007】建筑抢修 贪心+堆

Description

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

Input

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

Output

输出一个整数S,表示最多可以抢修S个建筑.N < 150,000; T1 < T2 < maxlongint

Sample Input

4

100 200

200 1300

1000 1250

2000 3200

Sample Output

3

bzoj1029

第一眼以为直接贪心+sort就能过,结果:10分(codevs交的)。当时觉得和UVA-11729很像……
我的贪心策略是:越早报废的越早修,若相等则修的越快越早修。

后来想想显然不对…

正解:先按报废时间由小到大排序,这样能使报废晚的能余出时间照顾报废早的。
然后从第一个开始,若当前建筑的修理时间+之前的总时间小于等于当前建筑的报废时间,则扔进堆里,ans++。
若大于,这时要从它前面所有建筑中选一个修理时间最长的(记为y)和它比较,
若当前建筑修理时间 > y,则不扔进堆中。
若当前建筑修理时间 < y,则把y替换成当前建筑。
这样能保证时间利用率最高,修理更多的建筑。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

const int size=200010;

struct edge{
    int a,b;
}l[size];

bool cmp(edge a,edge b)
{
    return a.b==b.b? a.a<b.a :a.b<b.b;
}

priority_queue<edge> q;
bool operator <(edge a,edge b)
{
    return a.a<b.a;
}


int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&l[i].a,&l[i].b);
    }
    sort(l+1,l+1+n,cmp);
    int ans=0,tot=0;
    for(int i=1;i<=n;i++)
    {
        if(l[i].a+tot<=l[i].b) {ans++;q.push(l[i]);tot+=l[i].a;}
        else
        {
            edge x=q.top(); q.pop();
            tot-=x.a;
            if(l[i].a<x.a) {q.push(l[i]);tot+=l[i].a;}
            else {q.push(x); tot+=x.a;}
        }
    }
    printf("%d",ans);
    return 0;
}

你可能感兴趣的:(【JSOI2007】建筑抢修 贪心+堆)