洛谷P2949题解

若想要深刻学习反悔贪心,传送门html


Description:node

\(n\) 项工做,每 \(i\) 项工做有一个截止时间 \(D_i\) ,完成每项工做能够获得利润 \(P_i\) ,求最大能够获得多少利润。c++

Method:算法

作这道题的时候并无想到反悔贪心,只是想到一个错误的贪心算法。按照截止时间为第一关键字,利润为第二关键字排序,统计一遍便可。学习

显然上面的贪心算法刻印被Hack掉。能够先不选择当前截止时间的利润,等一下选择下一个更大的利润,这样能够获得更大的最优解。spa

但咱们发现这个贪心策略错误的缘由是当前的最优解可能不是全局最优解,显然符合反悔贪心的思想。因而咱们用一个反悔堆维护最优解。code

假如知足题设条件(即没有超出截止时间)就分红两种状况:若当前的最优解比原来的最优解(堆顶)更优秀,咱们就更新全局最优解,把原来的最优解丢出去,再把当前的最优解放进去(即反悔策略);反之,就无论了。假如不知足特设条件,就把当前的最优解丢进堆里,更新全局最优解便可。htm

Code:blog

#include<bits/stdc++.h>
#define int long long 
#define Maxn 100010
inline void read(int &x)
{
    int f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}
using namespace std;
int n;
struct node
{
    int D,P;
    bool operator <(const node &x)const
    {
        return D<x.D;
    }
}job[Maxn];
priority_queue<int,vector<int>,greater<int> >qu;
signed main()
{
    //  freopen("Job.in","r",stdin);
    //  freopen("Job.out","w",stdout);
    read(n);
    for(int i=1;i<=n;i++)
    {
        read(job[i].D),read(job[i].P);
    }
    sort(job+1,job+n+1);
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(qu.size()>=job[i].D)//符合条件
        {
            if(qu.top()<job[i].P)//当前的最优解比原来的最优解(堆顶)更优秀
            {
                ans-=qu.top();//更新全局最优解
                qu.pop();//把原来的最优解丢出去
                qu.push(job[i].P);//把当前的最优解放进去
                ans+=job[i].P;//更新全局最优解
            }
        }else//不符合条件
        {
            qu.push(job[i].P);//把当前的最优解丢进堆里
            ans+=job[i].P;//更新全局最优解
        }
    }
    printf("%lld",ans);
    return 0;
}
相关文章
相关标签/搜索