洛谷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;
}
相關文章
相關標籤/搜索