题意:
有n个建筑,每个建筑有修复时间和截止时间,只有一个工人,建筑之间移动的时间不计,最多可以让多少个建筑在截止时间前修复好。
思路:典型的“给程序留一个后悔机会”的贪心。
贪心可以考虑下面三种种策略:
1.我最先想到的是先修复修复时间短的建筑a,但是可能它的截止时间很晚,而有一件截止时间很早的建筑b,做了a会导致不能修复b,而如果先做b不会耽误修复a,这时这个贪心不成立。
2.按照最晚开始修复的时间(截止时间减修复时间)早晚来做,可能有一件事最晚开始修复的时间很早,但是它的修复时间很长,在这之间完全可以做两件比他开始时间晚的事,这时这个贪心不成立。
3.按截止时间早的先做,但是会有一个问题,这个建筑的修复时间很长,本来可以修复后面几个建筑的时间全被它占了。
虽然上面的三种策略都不能一步到位,但是第三种方案可以给它一个后悔的机会。
1.当某个建筑不能修复时,我们就考虑是否反悔,如果之前修复的建筑中修复时间最大的比这个建筑的修复时间还长,那么替换掉之前修复时间的建筑。
2.替换掉后,因为当前的建筑比之前的建筑截止时间晚,所以也能完成,又因为当前建筑的修复时间更短,所以后面的建筑也能正常修复,不影响先前的结果还有可能多修复几个建筑。
3.要有反悔的机会就要用一个大根堆(优先队列,队首元素最大)去存每个修复了的建筑。
Code:
#include<bits/stdc++.h> #define js ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) using namespace std; typedef long long ll; struct node{ ll cost,end; }q[150005]; bool cmp(node a,node b){ return a.end<b.end; } int main() { int n; js; cin>>n; for(int i=1;i<=n;++i) cin>>q[i].cost>>q[i].end; sort(q+1,q+1+n,cmp); priority_queue<int>que; ll sum=0,ans=0; for(int i=1;i<=n;++i) { if(sum+q[i].cost<=q[i].end) { ++ans; sum+=q[i].cost; que.push(q[i].cost); } else if(que.top()>q[i].cost) { sum=sum-que.top()+q[i].cost; que.pop(); que.push(q[i].cost); } } cout<<ans<<endl; return 0; }