题目链接:https://www.acwing.com/problem/content/147/
容易想到一个贪心策略:在最优解中,对于每个时间(天数) t,应该在保证不卖出过期商品的前提下,尽量卖出利润前t大的商品。因此,我们可以依次考虑每个商品,动态维护一个满足上述性质的方案。
详细地说,我们把商品按照过期时间排序,建立一个初始为空的小根堆 (节点权值为商品利润),然后扫描每个商品:
1.若当前商品的过期时间(天数) t等于当前堆中的商品个数,则说明在目前方案下,前t天已经安排了t个商品卖出。此时,若当前商品的利润大于堆顶权值(即已经安排的t个商品中的最低利润),则替换掉堆顶(用当前商品替换掉原方案中利润最低的商品)。
2.若当前商品的过期时间(天数)大于当前堆中的商品个数,直接把该商品插入堆。
3.若当前商品的过期时间(天数)小于当前堆中商品的个数,哦!!!不可能,因为在第一种情况中,若当前商品的过期时间(天数) t等于当前堆中的商品个数,我们就会替换掉商品。
最终,堆里的所有商品就是我们需要卖出的商品,它们的利润之和就是答案。该算法的时间复杂度为O(N logN)。
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
struct node{
int val;
int time;
}nodes[10050];
bool operator <(const node &a, const node &b) {
return a.time<b.time;
}
int main(){
int n;
while (cin>>n) {
for (int i = 1; i <= n; ++i) {
cin>>nodes[i].val>>nodes[i].time;
}
sort(nodes+1,nodes+n+1);
priority_queue<int,vector<int>, greater<int> > q;
for (int i = 1 ; i <=n; ++i) {
int currentDay=nodes[i].time;
if (currentDay>q.size()) {
q.push(nodes[i].val);
}else {
int vals=q.top();
if(vals<nodes[i].val){
q.pop();
q.push(nodes[i].val);
}
}
}
int ans=0;
while (!q.empty()) {
ans+=q.top();
q.pop();
}
cout<<ans<<endl;
}
return 0;
}