题意

一共有n个设施需要修复,给出每个设施修复需要的时长,和每个设施被修复好的最晚时间(deadline),求最多能修复好多少个设施。

题解

贪心,首先先将所有修复任务按照最晚时间由小到大排序,如果本题开始时间固定,那就直接按顺序计算即可(hdoj2037),但是因为每个设施的开始时间是弹性的,所以我们应该让每个修复任务开始时间尽量较早,故可以建立一个堆,保存每个修复的设施的修复时长,按顺序判断每个任务是否可以完成。

即:考虑第i个任务,
若满足已选择的任务所花费的时间+当前修复任务所需时间<=此任务截止时间则res+1,并将此修复任务所需时长压入堆中。
若不满足:则判断当前任务时长是否小于已选择任务中时长最长的那个,若是,则用时长较短的任务替换时长较长的任务,为后面的任务留出更充裕时间。

Code

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<ll,ll> pii;

vector<pii> a;  //存储每个任务需要时间以及截止时间。
priority_queue<ll> pq;  //大根堆存储选择任务的时长

bool cmp(pii x,pii y){  //排序方式
    return x.second < y.second;
}

int main()
{
    int n;
    scanf("%d",&n);
    a.resize(n);
    for(int i = 0;i < n;++i)
        scanf("%lld%lld",&a[i].first,&a[i].second);
    sort(a.begin(),a.end(),cmp);    //按截止时间排序

    int res = 0;        //当前以选择任务
    ll now = 0;         //当前已选择任务的总时长
    for(int i = 0;i < n;++i){
        if(now + a[i].first <= a[i].second){    //若允许选择此任务
            pq.push(a[i].first);                //将任务时长压入堆中
            now += a[i].first;                  //更新总时长
            res++;                              //更新选择任务数量
        }
        else{
            if(!pq.empty() && a[i].first < pq.top()){   //满足当前任务所需时长更短
                int hd = pq.top();pq.pop();
                pq.push(a[i].first);
                now -= hd;                      //更新已选择任务以及总时长
                now += a[i].first;
            }
        }
    }
    printf("%d\n",res);
    return 0;
}