NC20154 [JSOI2007]建筑抢修(贪心)

题目链接

题意:
n有n个建筑,每个建筑有修复时间和截止时间
只有一个工人,假设路程不需要时间
最多可以让多少个建筑在截止时间前修复好
题解:
n<=15000n<=15000
感觉和那个老师教课问题很相似
想要教尽量多的课
只不过那个给的是起止时间,这个是需要时间和截止时间

贪心可以考虑几种策略
1.1.按需要时间短的先做
2.2.按最晚开始时间(即截止时间减需要时间)的早晚来做
3.3.按截止时间早的先做

首先分析第一种,先做时间短的
时间短的但是其实他截止时间很晚
你做了这件事,反而耽误了你一件截止时间早的事不能完成
所以这一种明显不成立

然后分析第二种
如果一件事最晚开始时间很早,但是他花费时间很长
在这之间你完全可以做两件比他开始时间晚的事
所以第二种也不成立

最后,说一下第三种
按截止时间早的先做,如果你当前时间如果满足截止时间前做完
那么就做这件事
但是如果这样的话,会出现一个问题
这件事的持续时间很长,导致你本来能做后面两件事的时间被这一件事占用了
所以每次需要有一个反悔的机会,就是可以重新选择
那么这个反悔的机会就用一个堆维护,让堆中放每件事的持续时间
top最大的时间在top,如果发现你这件事不能在截止时间前做完
那么就去堆中找最大的时间,是否比它的持续时间要长
如果比它要长那么就可以把堆中的那件事替换成这件事
由于是替换,结果是不变的,而且由于是按截止时间排序
那件事比他截止时间早,持续时间长都可以做完堆中的每一件
使你让在做那件事的时候做现在新替换的事,仍然可以使这个堆成立
AC代码

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

struct node{
    ll s,t;
}p[maxn];
bool cmp(node a,node b){
    return a.t<b.t;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)cin>>p[i].s>>p[i].t;
    sort(p+1,p+1+n,cmp);
    priority_queue<int>q;
    ll sum=0,ans=0;
    for(int i=1;i<=n;i++){
        if(sum+p[i].s<=p[i].t){
            ans++;sum+=p[i].s;
            q.push(p[i].s);
        }
        else if(q.top()>p[i].s){
            sum-=q.top();q.pop();
            sum+=p[i].s;q.push(p[i].s);
        }
    }
    cout<<ans<<endl;
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章