0x07.基本算法 — 贪心

本文是关于贪心算法的学习笔记,详细介绍了贪心算法的基本概念和证明方法,并通过USACO07NOV Sunscreen、USACO06FEB Stall Reservations、UVA1193 Radar Installation等典型题目进行实战解析,展示如何运用贪心策略解决区间覆盖、雷达安装和国王游戏等问题。同时,文中分享了学习过程中的经验与感悟,以及在编程实现中需要注意的细节和常见陷阱。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

声明:
本系列博客是《算法竞赛进阶指南》+《算法竞赛入门经典》+《挑战程序设计竞赛》的学习笔记,主要是因为我三本都买了 按照《算法竞赛进阶指南》的目录顺序学习,包含书中的少部分重要知识点、例题解题报告及我个人的学习心得和对该算法的补充拓展,仅用于学习交流和复习,无任何商业用途。博客中部分内容来源于书本和网络(我尽量减少书中引用),由我个人整理总结(习题和代码可全都是我自己敲哒)部分内容由我个人编写而成,如果想要有更好的学习体验或者希望学习到更全面的知识,请于京东搜索购买正版图书:《算法竞赛进阶指南》——作者李煜东,强烈安利,好书不火系列,谢谢配合。


下方链接为学习笔记目录链接(中转站)

学习笔记目录链接


ACM-ICPC在线模板


贪心

贪心是一种在每一次决策时都采用当前意义下最优策略的算法,因此,使用贪心算法要求问题的整体最优性可以由局部最优性导出。

贪心算法的正确性需要证明,常见的证明手段有:

  1. 微扰(邻项交换) 证明在任意局面下,任何对局部最优策略的微小改变都会造成整体结果变差,经常用于以排序为贪心策略的证明。
  2. 范围缩放 证明任何对局部最优策略作用范围的扩展都不会造成整体结果变差。
  3. 决策包容性
    证明在任意局面下,做出局部最优策略以后,在问题状态空间中的可达到集合包含了做出其他任何决策之后的可到达集合。换言之,这个局部最优解提供的可能性包含其他所有策略提供的可能性。
  4. 反证法
  5. 数学归纳法

0. USACO07NOV Sunscreen

洛谷题目链接 :https://www.luogu.com.cn/problem/P2887

在这里插入图片描述

其实本题可以看成区间覆盖问题,即求线段最多覆盖多少点,线段按右端点排序,防晒霜按防护值排序,只不过这里的线段有数量而已。

%%%yxc大佬,看完他的题解学到了一些实用的map的操作。
戳我看题解

整理了一下map 的操作:我是博客链接

yxc大佬的证明太强了,其实就是如果按照min排序,那么对于每一个防晒霜来说,不低于当前的牛的min,就一定不低于下一头牛的min,对于当前牛可用的两种防晒霜x和y来说,如果 s p f [ x ] < s p f [ y ] spf[x]<spf[y] spf[x]<spf[y]那么对于后面的牛来说,只能出现“x,y都能用”,“x,y都不能用”,和“x能用y不能用”这三种情况,因此这时选择用掉最大的是最优的。定好了一个边界以后,每次对于当前的牛,直接利用map中的upper_bound直接找到第一个大于max的防晒霜,并–找到第一个小于等于当前牛max的防晒霜,用掉。如果这种的防晒霜用完了,就从map 里erase掉。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<math.h>
#include<map>
#define ls (p<<1)
#define rs (p<<1|1)
#define over(i,s,t) for(register long long i=s;i<=t;++i)
#define lver(i,t,s) for(register long long i=t;i>=s;--i)
//#define int __int128
using namespace std;
typedef long long ll;//全用ll可能会MLE或者直接WA,全部换成int看会不会A,别动这里!!!
const ll N=2507;
const ll mod=1e9+7;
const double EPS=1e-5;//-10次方约等于趋近为0

int n,m;
pair<int,int>cow[N];
int main()
{
   
   
    cin>>n>>m;
    map<int,int>spfs;
    over(i,1,n)scanf("%d%d",&cow[i].first,&cow[i].second);
    over(i,1,m){
   
   
        int spf,cover;
        scanf("%d%d",&spf,&cover);
        spfs[spf]+=cover;
    }
    sort(cow+1,cow+1+n);
    int res=0;
    spfs[0]=spfs[1001]=n;
    for(int i=n;i>=1;--i){
   
   
        auto spf=spfs.upper_bound(cow[i].second);
        spf--;//这里的spf是map<>spfs的一个iterator,第一个大于cow[i].max的防晒霜
        //--之后就是最后一个小于等于cow[i].max的防晒霜了
        if(spf->first>=cow[i].first){
   
   
            res++;
            if(--spf->second==0)
                spfs.erase(spf);
        }
    }
    printf("%d\n",res);
    return 0;
}

1.USACO06FEB Stall Reservations (贪心)

题目链接:https://www.luogu.com.cn/problem/P2859

在这里插入图片描述

输入样例:

5
1 10
2 4
3 6
5 8
4 7

输出样例:

4
1
2
3
2
4

思路不会了看这里:
https://www.acwing.com/solution/AcWing/content/1060/

贪心的思路还是很好想很基础的,但是这道题代码写起来脑壳痛,其中的细节颇多,特别是这个queue里的bug找的我头疼,遂写成博客以警惕自己
你见过哪些意想不到的bug ?(常见代码使用误区,下次一定还犯)

这道题剩下的也没什么,就是要注意输出每头牛的组的时候要+1,因为这里是从0开始的

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<math.h>
#include<map>
#include<vector>
#include<queue>
#define ls (p<<1)
#define rs (p<<1|1)
#define over(i,s,t) for(register int i=s;i<=t;++i)
#define lver(i,t,s) for(register int i=t;i>=s;--i)
//#define int __int128
using namespace std;
typedef pair<int,int> PII;

typedef long long ll;//全用ll可能会MLE或者直接WA,全部换成int看会不会A,别动这里!!!
const int N=50010;
const ll mod=1e9+7;
const double EPS=1e-5;//-10次方约等于趋近为0

#define a cows
#define q heap
#define ans id

int ans[N];
pair<PII, int>a[N];
int n,m;
int main()
{
   
   
    cin>>n;
    for (int i = 0; i < n; i ++ ){
   
   
        cin>>a[i].first.first>>a[i].first.second;
        a[i].second=i;
    }
    sort(a,a+n)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁凡さん

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值