反悔贪心笔记
反悔贪心笔记
什么是反悔贪心?
贪心理论上是没有反悔一说的,贪心求的就是当前的最优解。但是当前的最优解不一定是全局最优解,所以要进行反悔操作
简单来说,就是当我们贪心时发现某一步不是最优解,我们就退后一步,换一个贪心策略
鉴于此,我们有两个反悔策略:
- 反悔堆:通过堆来维护当前贪心策略的最优解,若发现最优解不对,就退回上一步,更新最优解。
- 反悔自动机:作者还在学习中
例题详解
用时一定模型
USACO09OPEN 工作调度Work Scheduling
题意:
有
思路:
先按截止时间排序,然后再遍历,若没有冲突直接做,有冲突用小根堆反悔即可(因为小根堆存储的必定是最小值 )
code:
//Misty_Post coded at 24/1/25
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n;
struct nood{
ll dt;//截止时间
ll v;//价值
bool operator<(const nood &vv)const{//重载运算符 (小根堆需要)
if (v > vv.v) return 1;
return 0;
}
}es[1000000];
priority_queue<nood> q;//小根堆
bool cmp(nood x,nood y){
return x.dt<y.dt;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>es[i].dt>>es[i].v;
}
sort(es+1,es+1+n,cmp);
ll ans=0;
for(int i=1;i<=n;i++){
if(es[i].dt>q.size()){//有时间做这个任务
ans+=es[i].v;
q.push(es[i]);
}
else{//反悔
if(es[i].v>q.top().v){
ans-=q.top().v;
q.pop();
q.push(es[i]);
ans+=es[i].v;
}
}
}
cout<<ans;
}
价值一定模型
题意:
我们再来考虑这样一个问题,我们有 n 个任务,每个任务有截止日期和完成耗时。在同一时间我们只能去做一个任务。所有任务的价值都是一样的,问最多能完成多少个任务。
思路:
我们可以用大根堆维护截止日期,若可以安排任务直接安排,不能的话从大根堆中把耗时最长的任务丢掉,正确性显然
code
//Misty_Post coded at 24/1/25
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n;
struct nood{
ll dt;//截止时间
ll v;//持续时间
bool operator<(const nood &vv)const{//重载运算符 (小根堆需要)
if (v < vv.v) return 1;//更改这里可以变成大根堆
return 0;
}
}es[1000000];
priority_queue<nood> q;//大根堆
bool cmp(nood x,nood y){
return x.dt<y.dt;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>es[i].v>>es[i].dt;
}
sort(es+1,es+1+n,cmp);
ll ans=0;
for(int i=1;i<=n;i++){
if(es[i].dt>=ans+es[i].v){//有时间做这个任务
ans+=es[i].v;
q.push(es[i]);
}
else{
//cout<<"**";
if(es[i].v<q.top().v){
ans-=q.top().v;
q.pop();
q.push(es[i]);
ans+=es[i].v;
}
}
}
cout<<q.size();
}
FOR WHAT???!!!