1.问题类型
如果题目中的问题涉及最多个数时,我们需要去观察是不是不管解的大小,
他对于最后Ans的值的大小的影响都是一样的,那么因为他的影响都是一样的,
我们就可以去寻找最优满足的条件,这里就可以用贪心来求满足情况。
2.堆优化
堆在这里的重要作用有两个一个是加速(logN),一个是方便存储和比较。
一个堆,我们把耗费最大/最小的放在堆顶,那么也就意味着,
我们可以通过堆来对它的价值进行自动排序,我们可以那当前的来比较。
3.后悔操作
后悔操作是这类题目中的重难点,
因为这类问题并不是绝对的贪心,我们需要通过不断的check能否进行后悔操作来保证得到的是最优解,在通过进堆和出堆来调整最优结构。
4.Example
T1 麦乐烤翅
Description
在太行山 路上, 有一家麦乐鸡翅的生意火爆。 因为好吃, 所以卖的特别好。 排队的人就特别 多, 经常有很多人买不到鸡翅。
鸡翅会在每分钟烤出 Xi 个, 每分钟也只会卖给一个客人, 第 i 个客人需要买 Yi 个。 因为生 意火爆, 老板可以选择在这分钟不卖给这个客人鸡翅, 或者卖给这个顾客他需要的鸡翅, 如 果现在剩余的鸡翅不够, 那就肯定不能卖给这个客人。 无论这个客人能否买到鸡翅, 他必须 离开队伍。
现在给定 N 分钟, 且已经知道每分钟烤出的鸡翅个数 Xi, 也知道每个客人需要鸡翅的 Yi 个 数, 现在老板想知道, 如何合理安排卖给与拒绝, 最多可以满足多少人
Input
第一行一个正整数 N, 表示有 N 分钟的时间卖鸡翅
第二行 N 个用空格隔开的整数 X1, X2……Xn, Xi 表示第 i 分钟会有 Xi 个鸡翅烤出
第三行 N 个用空格隔开的整数 Y1, Y2……Yn, Yi 表示第 i 分钟的顾客需要 Yi 个鸡翅
Output
一个整数, 表示最多可以满足买到鸡翅的人数。
#include<cstdio>
#include<queue>
#define LL long long
#define RG register
using namespace std;
const int N=250005;
inline LL read()
{
RG LL x=0,w=1;RG char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*w;
}
LL n,Ans,now;
LL x[N],y[N];
priority_queue<int> Q;
int main()
{
n=read();
for(LL i=1;i<=n;i++)x[i]=read();
for(LL i=1;i<=n;i++)y[i]=read();
for(LL i=1;i<=n;i++)
{
now+=x[i];
if(now>y[i])Ans++,Q.push(y[i]),now-=y[i];
else if(!Q.empty()&&Q.top()>y[i])
{
now+=Q.top()-y[i];
Q.pop();Q.push(y[i]);
}
}
printf("%lld\n",Ans);
return 0;
}
Solution
这就是一个非常典型的堆+贪心的操作;
能卖就卖,如果比能满足需求,我们就拿这个需要的鸡翅,
与最多需要的鸡翅做比较,如果小于那个鸡翅数量,
我们就可以把那个pop掉,把这个数据push进来。
因为不管你消耗的鸡翅数量是多少,最终对于答案的影响都只是+1;
T2 工作安排
Description
Farmer John 有太多的工作要做啊!!!!!!!!为了让农场高效运转,他必须靠他的工作赚钱,每项工作花一个单位时间。
他的工作日从0时刻开始,有1000000000个单位时间(!)。在任一时刻,他都可以选择编号1~N的N(1 <= N <= 100000)项工作中的任意一项工作来完成。
因为他在每个单位时间里只能做一个工作,而每项工作又有一个截止日期,所以他很难有时间完成所有N个工作,虽然还是有可能。
对于第i个工作,有一个截止时间D_i(1 <= D_i <= 1000000000),如果他可以完成这个工作,那么他可以获利P_i( 1<=P_i<=1000000000 ).
在给定的工作利润和截止时间下,FJ能够获得的利润最大为多少呢?答案可能会超过32位整型。
Input
第1行:一个整数N.
第2~N+1行:第i+1行有两个用空格分开的整数:D_i和P_i.
Output
输出一行,里面有一个整数,表示最大获利值。
Solution
这个题要求求工资的最大值,我们先按时间截止sort一下
如果当前日期即堆内元素多少小于截止日期就疯狂push
但当不行时,我们就可以比较大根堆(堆顶为最小元素)
我们就可以将堆内全部变为满足最大工资的东西
再将堆内全部pop出来Ans求和就可以了
#include<bits/stdc++.h>
#define LL long long
using namespace std;
int n;
struct Work{
LL date,w;
bool operator < (const Work a)const {
return date<a.date;
}
}s[100000+5];
priority_queue< LL,vector<LL>,greater<LL> > Q;
int main(){
cin>>n;
LL ans=0;
for(int i=1;i<=n;i++)
cin>>s[i].date>>s[i].w;
sort(s+1,s+1+n);
for(int i=1;i<=n;i++){
if(Q.size()<s[i].date)Q.push(s[i].w);
else if(Q.top()<s[i].w){
Q.pop();
Q.push(s[i].w);
}
}
while(!Q.empty())ans+=Q.top(),Q.pop();
cout<<ans<<endl;
return 0;
}
5.实际运用需注意
有时候当给出的数据类型很多的时候我们需要用结构体入堆,
但cmp只用具有上述性质的影响因素