题目链接
题意:
有n个建筑,每个建筑有修复时间和截止时间
只有一个工人,假设路程不需要时间
最多可以让多少个建筑在截止时间前修复好
题解:
n<=15000
感觉和那个老师教课问题很相似
想要教尽量多的课
只不过那个给的是起止时间,这个是需要时间和截止时间
贪心可以考虑几种策略
1.按需要时间短的先做
2.按最晚开始时间(即截止时间减需要时间)的早晚来做
3.按截止时间早的先做
首先分析第一种,先做时间短的
时间短的但是其实他截止时间很晚
你做了这件事,反而耽误了你一件截止时间早的事不能完成
所以这一种明显不成立
然后分析第二种
如果一件事最晚开始时间很早,但是他花费时间很长
在这之间你完全可以做两件比他开始时间晚的事
所以第二种也不成立
最后,说一下第三种
按截止时间早的先做,如果你当前时间如果满足截止时间前做完
那么就做这件事
但是如果这样的话,会出现一个问题
这件事的持续时间很长,导致你本来能做后面两件事的时间被这一件事占用了
所以每次需要有一个反悔的机会,就是可以重新选择
那么这个反悔的机会就用一个堆维护,让堆中放每件事的持续时间
最大的时间在top,如果发现你这件事不能在截止时间前做完
那么就去堆中找最大的时间,是否比它的持续时间要长
如果比它要长那么就可以把堆中的那件事替换成这件事
由于是替换,结果是不变的,而且由于是按截止时间排序
那件事比他截止时间早,持续时间长都可以做完堆中的每一件
你让在做那件事的时候做现在新替换的事,仍然可以使这个堆成立
AC代码
#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=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);
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;
}