NO.66十六届蓝桥杯备战|基础算法-贪心-区间问题|凌乱的yyy|Rader Installation|Sunscreen|牛栏预定(C++)

区间问题是另⼀种⽐较经典的贪⼼问题。题⽬⾯对的对象是⼀个⼀个的区间,让我们在每个区间上做出取舍。
这种题⽬的解决⽅式⼀般就是按照区间的左端点或者是右端点排序,然后在排序之后的区间上,根据题⽬要求,制定出相应的贪⼼策略,进⽽得到最优解。
具体是根据左端点还是右端点排序?升序还是降序?⼀般是假设⼀种排序⽅式,并且制定贪⼼策略,当没有明显的反例时,就可以尝试去写代码。

P1803 凌乱的yyy / 线段覆盖 - 洛谷

按照区间左端点从⼩到⼤排序,当两个区间「重叠」的时候,我们必须要舍弃⼀个。为了能够「在移除某个区间后,保留更多的区间」,我们应该把「区间范围较⼤」的区间移除。
因此以第⼀个区间为基准,遍历所有的区间:

  • 如果重叠,选择「最⼩的右端点」作为新的基准;
  • 如果不重叠,那么我们就能多选⼀个区间,以「新区间为基准」继续向后遍历。

可以⽤「交换论证法」证明我们的贪⼼策略是最优解:
在从前往后扫描的过程中,当贪⼼解和最优解第⼀次出现不同决策时,关于两个区间a,b(其中a在左,b在右)的取舍,有下⾯两种情况:

  1. a, b两个区间不重叠:
  • 贪⼼解会将a 区间保留,然后以b 区间为基准,继续向后对⽐别的区间;
  • 最优解的选择有下⾯⼏种情况:
    a. 舍弃⼀个区间,那么必定不如贪⼼解,⽭盾。
    b. 以a区间为基准,向后对⽐。那更夸张了,我们已经按照区间左端点从⼩到⼤排好序了,如果a,b不重叠,那么a与后⾯的所有区间都不重叠,⽤a作为基准没有⼀点意义。还会选出与b重叠的区间。
    综上,如果「不重叠」的话,贪⼼解和最优解的决策应该是「⼀致」的。
  1. a, b 两个区间重叠,那么⽆论什么解,都需要「舍弃」⼀个区间:
  • 贪⼼解会保留两者「右端点较⼩」的区间,舍弃「右端点较⼤」的区间;
  • 最优解的选择就是,保留「右端点较⼤」的区间,舍弃「右端点较⼩」的区间。
    如果第⼆种决策能在此基础上得到最优解,那么我们把「右端点较⼤」区间换成「右端点较⼩」的区间是不受影响的。
    因为「较⼤区间」都和后续选择的区间「没有重叠」,这个较⼩的区间也必定「没有重叠」。因此,最优解可以调整成贪⼼解。
#include <bits/stdc++.h>
using namespace std;const int N = 1e6 + 10;int n;
struct node
{int l, r;
}a[N];bool cmp(node& x, node& y)
{return x.l < y.l;
}int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> n;for (int i = 1; i <= n; i++) cin >> a[i].l >> a[i].r;sort(a+1, a+1+n, cmp);int ret = 1;int r = a[1].r; //以第一个区间为基准for (int i = 2; i <= n; i++){int left = a[i].l, right = a[i].r;if (left < r) //有重叠{r = min(r, right);}else{ret++;r = right;}}cout << ret << endl;return 0;
}
UVA1193 Radar Installation - 洛谷

如图所⽰,当⼀个岛屿的「坐标」已知,其实可以计算出:当雷达放在x轴的「哪段区间」时,可以覆盖到这个岛屿
![[Pasted image 20250405192831.png]]

根据「勾股定理」得:ax的⻓度为 l = d 2 − y 2 l=\sqrt{ d^{2}-y^2 } l=d2y2 ,那么雷达所处的范围就是 [ x − l , x + l ] [x-l,x+l] [xl,x+l]。因此,针对每⼀个岛屿,我们都可以算出⼀个「能够覆盖它的区间」。
原问题就变成给定⼀些区间,所有互相重叠的区间⼀共有多少组。
按照区间「左端点从⼩到⼤」排序,当两个区间「重叠」的时候,为了后⾯能够「尽可能多的选出互相重叠的区间」,我们应该把「区间范围较⼤」的区间移除,因为选择较⼤区间会造成选出来的区间「不是互相重叠」的。
因此以第⼀个区间为基准,遍历所有的区间:

  • 如果重叠,选择「最⼩的右端点」作为新的基准;
  • 如果不重叠,那么我们就能多选⼀个区间,以「新区间为基准」继续向后遍历。
    可以⽤「反证法」证明,所有区间按照按照「左端点」排序之后,「互相重叠的区间」都是「相邻」的:
    假设所有区间按照左端点排序之后,存在互相重叠的区间,它们是不相邻的。也就是存在a,b,c,d四个区间,其中a,b,d互相重叠,但是a,b,c与它们三个不是互相重叠。
    设a, b, d区间重叠部分的范围是[x, y],那么c 的位置有两种情况:
  • c 在[x, y]的左侧,与实际不符:
    因为如果c在左侧,⼜要与a,b不是互相重叠,那么c的右端点必须要⼩于b的左端点,那就与所有线段按照左端点排序不符;
  • c 在[x, y]的右侧,也与实际不符:
    因为如果c在右侧,⼜要与a,b不是互相重叠,那么c的左端点必须要⼤于a,b的右端点的最⼩值;⼜因为d与a,b互相重叠,d的左端点就要⼩于a,b的右端点的最⼩值,与所有区间按照左端点排序不符。
    综上所述,所有区间按照按照「左端点」排序之后,「互相重叠的区间」都是「相邻」的
#include <bits/stdc++.h>
using namespace std;const int N = 1010;int n;
double d;
struct node
{double l, r;
}a[N];bool cmp(node& x, node& y)
{return x.l < y.l;    
}int main()
{int cnt = 0;while (cin >> n >> d, n && d){cnt++;bool flg = false;for (int i = 1; i <= n; i++){double x, y; cin >> x >> y;if (y > d) flg = true;double l = sqrt(d * d - y * y);a[i].l = x - l, a[i].r = x + l;}cout << "Case " << cnt << ": ";if (flg) cout << -1 << endl;else{sort(a+1, a+n+1, cmp);int ret = 1;double r = a[1].r;for (int i = 2; i <= n; i++){double left = a[i].l, right = a[i].r;if (left <= r){r = min(r, right);}else{ret++;r = right;}}cout << ret << endl;}}return 0;
}
P2887 [USACO07NOV] Sunscreen G - 洛谷

思考具体解法,从下⾯的情况中,筛选出没有特别明显的反例的组合:

  1. 区间按照左端点从⼩到⼤+防晒霜从⼩到⼤(优先选⼩);
  2. 区间按照左端点从⼩到⼤+防晒霜从⼤到⼩(优先选⼤);
  3. 区间按照左端点从⼤到⼩+防晒霜从⼩到⼤(优先选⼩);
  4. 区间按照左端点从⼤到⼩+防晒霜从⼤到⼩(优先选⼤);
  5. 区间按照右端点从⼩到⼤+防晒霜从⼩到⼤(优先选⼩);
  6. 区间按照右端点从⼩到⼤+防晒霜从⼤到⼩(优先选⼤)。
  7. 区间按照右端点从⼤到⼩+防晒霜从⼩到⼤(优先选⼩);
  8. 区间按照右端点从⼤到⼩+防晒霜从⼤到⼩(优先选⼤)。
    虽然看似很多,但是很容易在错误的策略中举出「反例」。
  • 区间按照左端点从小到大,优先选较小的点:
    ![[Pasted image 20250405210201.png]]

第一个区间选了a之后,b这个点就没办法分配了
实际上应该把a给第二个区间,b给第一个区间

  • 区间按照左端点从小到大,优先选较大的点:
    ![[Pasted image 20250405210416.png]]

第一个区间选了b之后,a这个点就没办法分配了
实际上应该把b给第二个区间,a给第一个区间

  • 区间按左端点从大到小,优先选较小的点:
    ![[Pasted image 20250405210732.png]]

第一个区间选了a之后,b这个点就没办法分配了
实际上应该把a给第二个区间,b给第一个区间

  • 区间按左端点从大到小,优先选较大的点:
    ![[Pasted image 20250405211155.png]]

较小的点能够更好地被后面的区间选择

  • 区间按右端点从小到大,优先选较小的点:
    较大的点能够更好地被后面的区间选择
  • 区间按照右端点从小到大,优先选较大的点:
    ![[Pasted image 20250405211529.png]]

第一个区间选了b之后,a这个点就没办法分配了
实际上应该把b给第二个区间,a给第一个区间

  • 区间按右端点从大到小,优先选较小的点:
    ![[Pasted image 20250405212006.png]]

把a给了第一个区间以后,b就没办法分配了
实际上应该把b给第一个区间,a给第二个区间

  • 区间按右端点从大到小,优先选较大的点:
    ![[Pasted image 20250405212450.png]]

第一个区间选了b之后,a这个点就没办法分配了
实际上应该把b给第二个区间,a给第一个区间

综上所述,有两种组合没有明显的反例,分别是:

  1. 区间按照「左端点从⼤到⼩」排序,防晒霜从⼤到⼩排序,「优先选择较⼤」的防晒霜;
  2. 区间按照「右端点从⼩到⼤」排序,防晒霜从⼩到⼤排序,「优先选择较⼩」的防晒霜。
    实际上两种情况都是正确的,我们取其⼀证明⼀下,另⼀种证明⽅式类似。

可以⽤「交换论证法」证明⽅式⼆的正确性:
从前往后依次⽐较「贪⼼解」和「最优解」针对每⼀个区间的决策,当找到第⼀个区间,它们的「分配决策不同」时:设贪⼼解⽤的是a防晒霜,最优解⽤的是b防晒霜,因为贪⼼解选的是最⼩的,所以有 a ≤ b a \le b ab
此时关于a 防晒霜的使⽤情况,可以分以下⼏种情况:

  1. a防晒霜在「最优解中没有使⽤」,那么我们可以直接⽤a防晒霜替换b防晒霜,此时最优解的「最优性」并没有损失,那么贪⼼解就和最优解决策⼀致;
  2. a防晒霜在「最优解的后续决策中使⽤了」,设b使⽤的区间是 [ x b , y b ] [x_{b},y_{b}] [xb,yb],a使⽤的区间是 [ x a , y a ] [x_{a},y_{a}] [xa,ya]
    易得:
    x b ≤ b ≤ y b , x a ≤ a ≤ y a x_{b} \le b \le y_{b}, x_{a} \le a \le y_{a} xbbyb,xaaya
    因为我们是按照右端点从⼩到⼤排序的,所以 y a ≥ y b y_{a} \ge y_{b} yayb
    综上:
    x a ≤ a ≤ b ≤ y b ≤ y a x_{a} \le a \le b \le y_{b} \le y_{a} xaabybya
    所以b也可以作⽤于「a作⽤的区间」,也就是在最优解中「a,b可以互换」,进⽽就转换成贪⼼解。
    因此,针对每⼀个位置,我们都可以把最优解在「不失去其最优性的前提下」,转化成「贪⼼解」
#include <bits/stdc++.h>
using namespace std;const int N = 2510;int n, m;
struct node
{int x;int y;
}a[N], b[N];bool cmp(node& x, node& y)
{return x.x > y.x;
}int main()
{cin >> n >> m;for (int i = 1; i <= n; i++) cin >> a[i].x >> a[i].y;for (int i = 1; i <= m; i++) cin >> b[i].x >> b[i].y;sort(a+1, a+1+n, cmp); //按左端点从大到小排序sort(b+1, b+1+m, cmp); //按阳光强度从大到小排序int ret = 0;for (int i = 1; i <= n; i++){int l = a[i].x, r = a[i].y;for (int j = 1; j <= m; j++){int w = b[j].x, &cnt = b[j].y;if (cnt == 0) continue;if (w < l) break;if (w > r) continue;ret++;cnt--;break;}}cout << ret << endl;return 0;
}
P2859 [USACO06FEB] Stall Reservations S - 洛谷

按照「起始时间」对所有奶⽜「从⼩到⼤」排序,然后「从前往后」依次安排每⼀头奶⽜,设这头奶⽜的产奶的时间区间是[a, b]

  • 在已经有⽜的所有⽜棚⾥,如果「结束时间⼩于a」,就可以把这头奶⽜放在这个⽜棚⾥⾯;如果有很多符合要求的,可以随便找⼀个。因为我们是按照起始时间从⼩到⼤排序,只要这些⽜棚都符合要求,对于后⾯的奶⽜⽽⾔也都符合要求。不妨找结束时间最早的,⽅便判断。
  • 如果所有已经有⽜的⽜棚的「结束时间都⼤于a 」,那么这头⽜只能⾃⼰单独开⼀个⽜棚。
    这个贪⼼策略是⽐较符合我们「常识」的,尽量优的安排每⼀头⽜
#include <bits/stdc++.h>
using namespace std;const int N = 5e4 + 10;int n;
struct node
{int x; //起始时间 / 结束时间int y; //终止时间 / 牛棚编号int z; //排序之前的编号bool operator<(const node& a) const{return x > a.x;}}a[N];int ret[N]; //存最终结果bool cmp(node& x, node& y)
{return x.x < y.x;
}int main()
{cin >> n;for (int i = 1; i <= n; i++){cin >> a[i].x >> a[i].y;a[i].z = i;}sort(a+1, a+1+n, cmp);int num = 1;priority_queue<node> heap;ret[a[1].z] = 1;heap.push({a[1].y, 1});for (int i = 2; i <= n; i++){int l = a[i].x, r = a[i].y;if (l <= heap.top().x) //无法放在已经分配的牛棚里{num++;ret[a[i].z] = num;heap.push({r, num});}else{node t = heap.top(); heap.pop();ret[a[i].z] = t.y;heap.push({r, t.y});}}cout << num << endl;for (int i = 1; i <= n; i++) cout << ret[i] << endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/75804.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用C语言控制键盘上的方向键

各位同学&#xff0c;大家好&#xff01;相信大家在学习C语言的过程中&#xff0c;都和我一样&#xff0c;经常使用scanf函数来接受字符&#xff0c;数字&#xff0c;这些标准输入信息&#xff0c;来实现自己设计的程序效果。 而我突然有一天&#xff08;对就是今天&#xff09…

特殊的质数肋骨--dfs+isp

1.dfs全排列组数&#xff0c;an记得还原 2.如果范围确定且只比较质数&#xff0c;isp比线性筛快&#xff0c;主要这个范围太大了 https://www.luogu.com.cn/problem/P1218 #include<bits/stdc.h> using namespace std; #define N 100011 typedef long long ll; typed…

定积分的应用(4.39-4.48)

battle cry 前言4.394.404.414.424.434.444.454.464.474.48 前言 题目确实比较多。slow down and take your time. 4.39 狂算了一遍&#xff0c;然后发现不是计算出问题了&#xff0c;是积分上下限写错了。还有把函数代进去也出了一点问题。 点火公式一家人我不记得&#x…

如何高效使用 Ubuntu 中文官方网站

Ubuntu 中文官方网站 一、快速导航与核心模块 首页焦点区 顶部菜单栏:快速访问「下载」「文档」「支持」「商店」等核心功能。轮播图区:展示最新版本(如 Ubuntu 24.04 LTS)和特色功能(如 Ubuntu Pro 订阅服务)。搜索框:支持中文关键词搜索(如 "边缘计算"),…

form实现pdf文件转换成jpg文件

说明&#xff1a; 我希望将pdf文件转换成jpg文件 请去下载并安装 Ghostscript&#xff0c;gs10050w64.exe 配置环境变量&#xff1a;D:\Program Files\gs\gs10.05.0\bin 本地pdf路径&#xff1a;C:\Users\wangrusheng\Documents\name.pdf 输出文件目录&#xff1a;C:\Users\wan…

Spring 核心技术解析【纯干货版】- XVIII:Spring 网络模块 Spring-WebSocket 模块精讲

在现代 Web 开发中&#xff0c;实时通信已成为提升用户体验的关键技术之一。传统的 HTTP 轮询方式存在较高的延迟和带宽开销&#xff0c;而 WebSocket 作为一种全双工通信协议&#xff0c;能够在客户端和服务器之间建立持久连接&#xff0c;实现高效的双向数据传输。 Spring 框…

VirtualBox安装FnOS

1.下载FnOS镜像 下载网址&#xff1a; https://www.fnnas.com/2.创建虚拟机 虚拟机配置如图所示&#xff08;注意操作系统类型和网卡配置&#xff09; &#xff08;注意启动顺序&#xff09; 3.启动虚拟机 网卡类型选择桥接的Virtual Adapter 如果没有IP地址或者IP地址无法…

java根据集合中对象的属性值大小生成排名

1&#xff1a;根据对象属性降序排列 public static <T extends Comparable<? super T>> LinkedHashMap<T, Integer> calculateRanking(List<ProductPerformanceInfoVO> dataList, Function<ProductPerformanceInfoVO, T> keyExtractor) {Linked…

grep命令: 过滤

[rootxxx ~]# grep root /etc/passwd [rootxxx ~]# grep -A 2 root /etc/passwd -A #匹配行后两行 [rootxxx ~]# grep -B 2 root /etc/passwd -B #匹配行前两行 [rootxxx ~]# grep -C 2 root /etc/passwd -C #前后2行 [rootxxx ~]# grep -n root /…

二十种中药果实识别分类系统,Python/resnet18/pytorch

二十种中药果实识别分类系统,Python/resnet18/pytorch 基于pytorch训练, resnet18网络&#xff0c;可用于训练其他分类问题&#xff0c;也可自己重新训练 20类中药材具体包括&#xff1a;(1) 补骨脂&#xff0c;(2) 草豆蔻&#xff0c;(3) 川楝子&#xff0c;(4) 地肤子&…

SpringBoot启动run方法分析

SpringBoot启动run方法分析 1.场景引入 在项目启动的时候&#xff0c;有时候我们需要在启动的时候&#xff0c;执行一些逻辑。 比如说&#xff0c;项目启动的时候&#xff0c;我想把一些热门商品的数据加载到缓存中去&#xff1b; 比如说&#xff0c;自定义了一个netty服务…

Linux信号——信号的处理(3)

信号是什么时候被处理&#xff1f; 进程从内核态&#xff0c;切换到用户态的时候&#xff0c;信号会被检测处理。 内核态&#xff1a;操作系统的状态&#xff0c;权限级别高 用户态&#xff1a;你自己的状态 内核态和用户态 进程地址空间第三次 所谓的系统调用本质其实是一堆…

MySQL篇(四)事务相关知识详解

MySQL篇(四&#xff09;事务相关知识详解 MySQL篇(四&#xff09;事务相关知识详解一、事务的特性&#xff08;ACID&#xff09;原子性&#xff08;Atomicity&#xff09;一致性&#xff08;Consistency&#xff09;隔离性&#xff08;Isolation&#xff09;持久性&#xff08;…

SpringBoot定时任务深度优化指南

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 SpringBoot定时任务深度优化指南 引言 在分布式系统架构中&#xff0c;定时任务是实现业务逻辑自动化的重要组件。SpringBoot通过Scheduled注解提供了便捷的…

MySQL表结构导出(Excel)

目录 一、java实现MySQL表结构导出&#xff08;Excel&#xff09; 二、python实现MySQL表结构导出&#xff08;Excel&#xff09; 又到了写毕设的时候了&#xff0c;计算机专业在写论文第四章系统设计的时候肯定会遇到和我一样的难题——要在论文中将数据库的表结构以表格形式…

Android使用OpenGL和MediaCodec渲染视频

目录 一&#xff0c;借助MediaCodec封装解码工具类VideoCodec 二&#xff0c;使用OpenGl绘制视频封装SoulFilter 一&#xff0c;借助MediaCodec封装解码工具类VideoCodec /*** 解码工具类* 解码完成后的数据 通过 ISurface 回调出去*/ public class VideoCodec {private ISu…

day39——输入操作:多值输入

数组输入&#xff1a; int main() {//***** 1、多值输入&#xff08;C&#xff09;/*输入&#xff1a;3 --> 3个值5 4 9*/int n;cin >> n; //输入个数const int MAX_SIZE 0xFFFF;//限定最大个数int a[MAX_SIZE];for (int i 0; i < n; i) {//用 n 作控制输入…

第九课:LoRA模型的原理及应用

文章目录 Part.01 3种LoRA的使用方式Part.02 5种LoRA的应用方向Part.01 3种LoRA的使用方式 LoRA能够在家用级设备上训练,实现对Checkpoint在某些方面的微调使用Lora的三种方式:放置Lora模型到目录中,然后作为提示词的一部分输入。点击生成按钮下面的“画”,然后打开Additio…

Cortex-M3 NVIC可以控制异常向量表的哪些部分

Cortex-M3 的 NVIC(嵌套向量中断控制器)不直接控制整个异常向量表,但可以管理向量表中与中断相关的部分行为。以下是 NVIC 对异常向量表的具体控制范围和相关机制: 1. NVIC 直接控制的部分 NVIC 主要管理 外部中断(IRQ) 和部分 系统异常 的行为,但对向量表本身的存储位…

双向链表增删改查的模拟实现

本章目标 0.双向链表的基本结构 1.双向链表的初始化 2.头插尾插 3.头删尾删 4.查找与打印 5.在指定位置之前插入数据/在指定位置之后插入数据 6.在指定位置之前删除数据/在指定位置之后删除数据 7.销毁链表 0.双向链表的基本结构 本章所实现的双向链表是双向循环带头链表,是…