【算法】反悔贪心

通常来讲,贪心向来是取局部最优解,但是局部最优解最后不一定构成整体最优解,因而就有了反悔这个操作,来优化贪心。
而构成反悔贪心,通常会有一个限制条件。
例如,我们假设数组array{1,5,6,7,2,6,7,9,4,3,5,1};如果我们要求取k个数,使其取得最大值,显然此时我们的贪心策略是对array数组进行排序,取前k大的数据加起来就得到结果。但是当我加一个限制条件,不允许取相邻的两个数,也就是说当你取了位置i上的数时,位置i-1和位置i+1的值就不能取了,此时若按照上述贪心策略取贪心,则不能确保整体最优解。
举个最简单的例子,对于{4,5,2},如果我们取了5,则不能取4和2,但我们发现我们可以不取5,转而取4和2,而此时获得的值为4+2=6,是大于5的。这时我们发现我们第一个贪心策略是不完美了,我们需要进行反悔操作,才能达到最优解。
那么如何进行反悔操作呢。我们假设数值5对应的位置为i;则4的位置为i-1,2的位置为i+1,namo我们可以设一个大根堆存储各个元素的值及其对应的位置,首先我们采取最开始的贪心策略,我们把5给拿走,此时我们可以处理一个反悔操作,令a[i] = a[i+1] +a[i-1] -a[i] ;并将这个更新的值加入大根堆中,若我们可以取到这个值,显然更新后的a[i]含有的a[i] 项就会和我们之前贪心选择的a[i] 项消掉,留下a[i+1] 和a[i-1],这便完成了一次反悔贪心,以此类推,从小及大,最终即可得到最优解。
在这里我推荐两道例题去具体熟练一下操作:
一、洛谷的种树.
AC代码:

/*
 * @Author: csc
 * @Date: 2021-04-05 15:29:23
 * @LastEditTime: 2021-04-06 19:32:17
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \code_formal\cf\CF_712_4_.cpp
 */
#include <bits/stdc++.h>
#define pr printf
#define sc scanf
#define sf(n) scanf("%d", &n)
#define sff(n1, n2) scanf("%d %d", &n1, &n2)
#define sfff(n1, n2, n3) scanf("%d %d %d", &n1, &n2, &n3)
#define sl(n) scanf("%lld", &n)
#define sll(n1, n2) scanf("%lld %lld", &n1, &n2)
#define slll(n1, n2, n3) scanf("%lld %lld %lld", &n1, &n2, &n3)
#define for0(i, n) for (i = 0; i < n; i++)
#define for1n(i, n) for (i = 1; i <= n; i++)
#define foran(i, a, n) for (i = a; i <= n; i++)
#define forna(i, a, n) for (i = n; i >= a; i--)
#define pb push_back
#define fi first
#define se second
#define int long long
#define endl '\n'
#define mem(ara, n) memset(ara, n, sizeof(ara))
#define memb(ara) memset(ara, false, sizeof(ara))
#define all(x) (x).begin(), (x).end()
#define sq(x) ((x) * (x))
#define sz(x) x.size()
const int N = 2e5 + 100;
const int mod = 1e9 + 7;
namespace fastIO
{
   
    inline void input(int &res)
    {
   
        char c = getchar();
        res = 0;
        int f = 1;
        while (!isdigit(c))
        {
   
            f ^= c == '-';
            c = getchar();
        }
        while (isdigit(c))
        {
   
            res = (res << 3) + (res << 1) 
  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值