Supermarket

题目大意:

超市有n种商品,每个商品都有一个利润和保质期,超市每天只可以卖一种商品,求超市在保质期内卖出商品可获得的最大利益。

思路:
贪心+二叉堆优化
在最大的保质期时间内找出利润最大的商品卖掉,这个贪心思路是正确的,我们会发现我们的每一个选择都会被商品的保质期影响,即我们必须在商品的保质期内卖出商品,所以我们可以将保质期与可选择的次数相结合,得到以下方法:
将每种商品的保质期按从小到大顺序排序。
使用小根堆维护已经选择商品的价值,然后继续选择商品,这时会有这两种情况:
1.当前商品的保质期大于已经选择商品的次数,直接将此商品加入选择之中;
2.当前商品的保质期等于已经选择商品的次数,将这个商品的价值与小根堆的堆顶作比较,如果大于即替换,否则不变。
因为每次都选择最优的选项,保证了算法的正确性。
代码:

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define lowbit(x) x&(-x)

typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll, ll> pll;

const int N = 1e4+5;
const ll mod = 1e9+7;
const int INF = 0x3f3f3f3f;
const double eps =1e-9;
const double PI=acos(-1.0);
const int dir[8][2]={-1,0,1,0,0,-1,0,1,1,1,1,-1,-1,1,-1,-1};

ll qpow(ll x,ll y){
    ll ans=1,t=x;
    while(y>0){
        if(y&1)ans*=t,ans%=mod;
        t*=t,t%=mod;
        y>>=1;
    }
    return ans%mod;
}

int p[N],t[N],c[N];
bool cmp(int x,int y){return t[x]<t[y];}
void solve(){
    int n;
    while(cin>>n){
        for(int i=1;i<=n;i++)cin>>p[i]>>t[i];
        for(int i=1;i<=n;i++)c[i]=i;
        sort(c+1,c+n,cmp);
        priority_queue<int,vector<int>,greater<int>>q;
        int sum=0;
        for(int i=1;i<=n;i++){
            int x=c[i];
            if(t[x]>q.size())q.push(p[x]),sum+=p[x];
            else {
                if(q.top()<p[x])sum+=p[x]-q.top(),q.pop(),q.push(p[x]);
            }
        }
        cout<<sum<<endl;
    }
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    //int t;cin>>t;
    //while(t--)solve(),cout<<'\n';
    solve();
    return 0;
}