贪心tricks总结
贪心题一般没有什么技巧,多做题积累经验。
对于结论或策略,大胆猜想,小心求证,注意使用数据结构优化/结合其他算法。
一般类贪心
主要是证明贪心的正确性。
H. Fight Against Monsters
先用二分求出每个怪需要打的次数。
问题转化为
一个排列的答案是
考虑邻项交换
如果交换更优,应满足
即
按照属性升序排序即可。
打怪兽2
对于
对于
设现在还剩血量
由
只能有
进一步
即
按照
反悔贪心
P2949 [USACO09OPEN] Work Scheduling G
题目大意:给个任务有一个截止时间,每个时间安排一个任务,求最大利润。
朴素贪心想法:按照截止时间排序,优先做利润大的。
问题在于如果后面出现了利润更大的,但前面的已经被安排满了,就会导致贪心策略错误,故这种情况就要反悔操作。
使用一个优先队列维护一个做过的决策集合,如果当前任务还能做,直接加入集合。否则,从之前的决策中取利润最小的替换掉。
这个操作等价于没有做之前的利润小的任务,直接做了利润更大的任务,从局部最优满足了全局最优。
sort(a+1,a+1+n);
for(int i=1;i<=n;++i)
{
if(a[i].d<=Q.size())
{
if(Q.top()>a[i].p) continue;
else
{
int x=Q.top();
Q.pop();
ans+=a[i].p-x;
Q.push(a[i].p);
}
}
else
{
ans+=a[i].p;
Q.push(a[i].p);
}
}
P4053 [JSOI2007] 建筑抢修
题目大意:每个任务有所需时间和截止时间,求最多能安排多少任务。
朴素贪心:按照截止时间排序,扫一遍判断是否能做。
此时就会有无法做的任务,我们会直接舍弃,给前面一个任务很多的时间,贪心错误,考虑反悔。
用一个大根堆维护决策集合,具体维护其时间。如果当前时间能够做这个任务,就直接做。否则,一定有一个任务是不能做的,只能尽可能地压缩当前时间,以保证后面能安排更多的任务。于是考虑从大根堆中取出耗费时间最多的决策去除,消去其贡献。
注意一定要先贪心再反悔。
贪心证明:
假设我们确定了要选
记之前已经用的时间为
对于相邻的
交换后有
整理一下,有
故是按照截止时间排序。
int now=0,cnt=0;
for(int i=1;i<=n;++i)
{
now+=a[i].t1;
Q.push(a[i].t1);
if(now<=a[i].t2)
{
++cnt;
}
else
{
int x=Q.top();
Q.pop();
now-=x;
}
}
然后就可以通过转化,将这个问题建模为其他问题:
Zabuton
将每个人抽象成任务,拥有任务所需时间和截止时间,那么添加的砖就是任务所需时间,最初的砖不能超过
for(int i=1,p,h;i<=n;++i)
{
h=read(),p=read();
a[i].t1=p,a[i].t2=p+h;
}
本文作者:vanueber
本文链接:https://www.cnblogs.com/vanueber/p/18710140
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步