题目链接
这道题在李煜东进阶指南里讨论了两种解法,都是基于贪心的思路,借助不同的数据结构,从而很好的达到目的。这里讨论二叉堆的解法。
看到这道题,想到了白书汽车加油问题,在某个站点加不加油取决于在后面行驶过程中油是否用完,如果油用完了,就选择所经过加油最多的站点加油。油用完了再进行加油,相当于在之前就选择了加油。
此题也是一样,基于一种贪心的策略,先按照过期时间从小到大排序,创建小根堆,堆中维护的是暂时选择的商品的利润。遍历每一个商品,如果当前商品没有过期,则直接把这件商品扔进堆中;否则与堆顶元素比较,如果大于堆顶元素的利润,则用这件商品替换掉堆顶的商品。虽然不会证明,但这样一定是最优的。
注意小根堆的创建,这里也可以创建大根堆,然后将利润的相反数放进大根堆
#include <bits/stdc++.h>
using namespace std;
const int N = 10010;
struct Node{
int p;
int d;
bool operator<(const Node& w)const{
return d<w.d;
}
}node[N];
int main()
{
int n;
while(scanf("%d",&n)!=EOF){
for(int i=1;i<=n;i++) scanf("%d%d",&node[i].p,&node[i].d);
sort(node+1,node+1+n);
priority_queue<int,vector<int>,greater<int> > pq;
int now = 0;
for(int i=1;i<=n;i++){
if(node[i].d<=now && pq.top()<=node[i].p){
pq.pop();
pq.push(node[i].p);
}else if(node[i].d>now){
pq.push(node[i].p);
now++;
}
}
long long ans = 0;
while(!pq.empty()){
ans += pq.top();
pq.pop();
}
printf("%lld\n",ans);
}
return 0;
}