反悔贪心

目录:

  • 个人理解
  • 反悔贪心的分类
    • 反悔自动机
    • 反悔堆
  • 例题简析及代码

一、个人理解:

贪心本身是没有反悔操作的,贪心求的就是当前的最优解。但当前的最优解有可能是局部最优解,而不是全局最优解,这时候就要进行反悔操作。

反悔操作指的是这一步的贪心不是全局最优解,我们就退回去一步(人工或自动判断),换一种贪心策略。按照判断方式的不同可以分为反悔自动机反悔堆两种方法。


二、反悔贪心的分类:

  1. 反悔自动机:

    即设计一种反悔策略,使得随便一种贪心策略都可以得到正解。

    基本的设计思路是:每次选择直观上最接近全局最优解的贪心策略,若发现最优解不对,就想办法自动支持反悔策略。(这就是自动机的意思)

    具体题目具体分析。

  2. 反悔堆:

    即通过(大根堆、小根堆)来维护当前贪心策略的最优解,若发现最优解不对,就退回上一步,更新最优解。

    由于堆的性质,使得堆的首数据一定是最优的,这就可以实现快速更新最优解


三、例题简析及代码

  1. USACO09OPEN 工作调度Work Scheduling (反悔堆)

    Description:

    有 \(n\) 项工作,每 \(i\) 项工作有一个截止时间 \(D_i\) ,完成每项工作可以得到利润 \(P_i\) ,求最大可以得到多少利润。

    Method:

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

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

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

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

    Code:

    #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;
    }
  2. CF865D Buy Low Sell High

    咕咕咕……

  3. BZOJ2151 种树

    咕咕咕……

原文地址:https://www.cnblogs.com/nth-element/p/11768155.html

时间: 2024-08-26 08:47:54

反悔贪心的相关文章

51nod 1476 括号序列的最小代价 (括号题套路+反悔贪心)

题意:给一串只有'(' , ')' , '?' 的括号序列,每个?可以变成)或者(,代价分别为bi和ai,求变成合法序列的最小代价 思路:学习自最近的网络赛&&51nod贪心专题视频的思想,“反悔”,一般在获取收益有限制的情况下使用 先按某种“优”的策略贪心,如果不满足限制条件了,取一个修改后代价尽可能小的状态修改成满足条件的状态,得到新的满足限制下的最优解 这种贪心常常可以借助优先队列实现 然后是括号题的套路:把(当做1,把)当做-1,做前缀和 这题中,先当做所有的?都换成右括号,这是显

【贪心】10.24assassin

题目分析 没有题目分析…… 寄存一下神奇反悔贪心 1 #include<bits/stdc++.h> 2 const int maxn = 100035; 3 4 struct node 5 { 6 int a,b; 7 node(int x=0, int y=0):a(x),b(y) {} 8 bool operator < (node x) const 9 { 10 return a < x.a; 11 } 12 }a[maxn],b[maxn]; 13 int T,n,m,m

CF1271D Portals dp 贪心

地址 首先可以观察得出:  如果可以defence 城堡i有多个城市,那么选择最后一个城市再考虑是否defence该城堡是最优方案 第一种方法 可以采用dp 因为发现士兵数量C 小于5000  所以设置dp[i]表示攻打到当前城堡时,士兵数剩余i个所取得的最大贡献 第二种方法 可以用优先队列优化 要求出第i个城市最多可以使用多少个额外的士兵非常的麻烦 可以用反悔贪心法 如果能占领城市那么就去占领, 如果攻打下一个城市缺人, 那么可以将之前派去的士兵召集回来 用一个小顶堆存放派去的士兵,这样如果召

复习及学习计划

需学习 近期优先 超联赛 1.字符串相关:KMP.AC自动机 2.Pufer序列.卡特兰数 3.Tarjan 4.crt.excrt 5.莫比乌斯反演(YY的gcd) 6.高斯消元及解的判断 7.网络流 8.反悔贪心(cow) 9.二维线段树 10.CDQ解三维偏序 原文地址:https://www.cnblogs.com/hzoi-yzh/p/11650728.html

CSP-S模拟题(补几天的坑,62~69)

模拟62 Graph 很显然的一个性质是旅行次数为一个联通块中边数/2向下取整,树DP+贪心走一边DFS即可求出方案 #include<bits/stdc++.h> using namespace std; typedef pair<int,int> P; typedef pair<P,int> D; struct edge{ int u,v; inline int get(int x){return x==u?v:u;} }e[200050]; int N,M,las

2017.8.7 联考 就 贪心(有反悔策略)

[背景描述] 一排 N 个数, 第 i 个数是 Ai , 你要找出 K 个不相邻的数, 使得他们的和最大. 请求出这个最大和. [输入格式] 第一行两个整数 N 和 K. 接下来一行 N 个整数, 第 i 个整数表示 Ai . [输出格式] 一行一个整数表示最大和, 请注意答案可能会超过 int 范围 [样例输入] 3 2 4 5 3 [样例输出] 7 [数据范围] 对于 20% 的数据, N, K ≤ 20 . 对于 40% 的数据, N, K ≤ 1000 . 对于 60% 的数据, N,

可以反悔的贪心

第一次遇到这种题,但是我觉得还是不严谨,希望能御剑有同感的朋友交流一下. https://www.luogu.org/problem/P4053 我写的代码是这样的: #include <bits/stdc++.h> using namespace std; #define ll long long #define re register inline long long read() { char ch = getchar(); long long x = 0, f = 1; while(c

[CTSC2010]星际旅行(带反悔的贪心)

题目 有一棵树,限制从每个点出发的次数最多为\(c_i\),对于每个点i,求1到i的路径最多经过多少次边\(,(n\leq 40000)\),保证每个点的\(c\)大于其入度 解法1 直接莽?拆点,中间连容量为\(c_i\)费用为0的边,点与点之间连容量为inf费用为1的边,从1到每个点i跑一次最大费用最大流即可 显然过不了本题数据 解法2 考虑树形DP解决这个网络流问题 递推解决问题?本题难点在于:确定递推顺序然后确定一个点的答案 由于每个点的\(c\)都大于其入度,那么从1开始一定可以将所有

【BZOJ 2151】 2151: 种树 (贪心+堆)

2151: 种树 Description A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树.园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n.并且每个位置都有一个美观度Ai,如果在这里种树就可以得到这Ai的美观度.但由于A城市土壤肥力欠佳,两棵树决不能种在相邻的位置(i号位置和i+1号位置叫相邻位置.值得注意的是1号和n号也算相邻位置!).最终市政府给园林部门提供了m棵树苗并要求全部种上,请你帮忙设计种树方案使得美观度总和最大.如果无法将m棵树苗