第三十八章 贪心算法——区间问题(上)

news2024/11/19 5:52:43

第三十八章 贪心策略——区间相关问题

  • 一、什么贪心策略?
  • 二、区间问题合集
    • 1、思路:
    • 2、问题1: 区间选点
      • (1)问题
      • (2)思路和证明
        • a.思路
        • b.证明
      • (3)代码
    • 3、问题2:
      • (1)问题
      • (2)思路和证明
        • a.思路
        • b、证明
      • (3)代码

一、什么贪心策略?

贪心策略是一种活在当下,偏短视的策略。每次做的都是对当下最好的选择,然后从局部最优最终推出整体最优。

二、区间问题合集

1、思路:

对于贪心策略中的区间问题往往是利用左右端点去排序,然后猜测一些性质。

2、问题1: 区间选点

(1)问题

在这里插入图片描述

(2)思路和证明

a.思路

这道题简单的来说,就是我们选出几个点,这几个点所在的区间能包含所有我们输入的区间,那么在满足这个条件的前提下,我们选出一个最小值,即我们找最少的点。

那么怎么找呢?

我们先把输入的区间映射到数轴上来看这个问题:
在这里插入图片描述

如上图所示,我们将所有的区间都映射到数轴上,此时我们尝试着去选点,对于前两个区间而言,我们的A1和A2是我们选的点。很明显,我们选的点越靠右越好。也就是说对于当前的来看,我们选的越靠右越好,这就是当下的最优策略。比如图上的A2点和A1点。

根据这个现象,我们总结出下面的解题思路:

  • 1、将区间映射到数轴上(按照右端点从小到大排序)

  • 2、按照右端点从小到大枚举区间,看下一个区间的左端点是否小于当前的右端点。

    • 如果小于的话,说明当前区间的右端点包含在下一个区间内,也就是说我们选择当前区间的右端点可以包含两个区间。
    • 如果大于的话,那么很明显,由于我们的右端点从小到大,所以下一个区间的右端点肯定是当前的右端点,同时下一个区间的左端点也大于我们当前的右端点,这就说明我们当前的右端点不包含在下一个区间内。
  • 3、如果是第一种情况,那么我们不用继续在下一个区间内选点,如果是第二种情况,则我们需要选上下一个区间的右端点。

我们先来解决第一个问题,能不能按照左端点来排序?
在这里插入图片描述
上面的图是按照左端点排序的,如图中的所示,我们的橙色线所对的点是最优的。但是在左端点排序的条件下,我们按照刚才的步骤来看,我们会取出L1和L2的右端点,其实实际上我们只需要选一个。

因此我们只能选择右端点排序。

(其实,如果按照左端点排序,需要从后往前遍历,这种做法也是可以的。)

b.证明

证明:反证法
我们假设存在一个最优解,优于我们的上述贪心算法计算出来的解。

因为这个最优解不符合我们的贪心算法,也就是说,这个最优解中的某些点选的不是最右侧的点。

那么分为以下三种情况:
在这里插入图片描述
在这种情况下,我们的最优解所选的绿色点是只覆盖了一个区间,因此它需要在下一个区间再选一个点,所以如果只有这一个点和我们的贪心算法得出的结果不一样的话,假设的最优解至少比我们的算法结果多1。

在这里插入图片描述
这是第二个情况,但此时我们发现,这两个点是等价的,都没有覆盖下一个点。此时假设的最优解等于我们的算法结果。

第三种情况:
在这里插入图片描述
第三种情况就是二者都覆盖了下一个区间,那么二者也是等价的,因此假设的最优解和我们的算法结果也是一样的。

综合上述三种情况,我们假设的最优解大于等于我们的算法结果的,而我们的题目是找一个最小值,也就是说假设的最优解并不是最优的,矛盾,故我们的算法是正确的。

(3)代码

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef pair<int,int> PII;
const int N=1e5+10;
PII a[N];
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        a[i].first=r,a[i].second=l;
    }
    sort(a,a+n);
    int ans=0,ed=-2e9;
    for(int i=0;i<n;i++)
    {
        if(ed<a[i].second)
        {
            ans++;
            ed=a[i].first;
        }
    }
    cout<<ans<<endl;
}

3、问题2:

(1)问题

在这里插入图片描述

(2)思路和证明

a.思路

我们还是先将这些区间映射到我们的数轴上。这道题的话,其实和上面那道题的做法是一模一样的。我们把相交的区间看成一个集合。那么我们最终的答案其实就是集合的数量。

我们看下面的这个例子:
在这里插入图片描述
对于每个集合而言,我必定只能选1个区间,这是肯定的。

并且我们尽可能选择一个集合中右端点靠左的那一个,为什么呢?

因为为了能够尽可能多的去选出不相交的区间,我们一定要为后续的区间腾出最大的空间

所以,如果我们发现一个集合中最靠左的那个区间和某个不在集合内的区间不相交的话,我们就可以将这个不相交的区间分成下一个集合。

那我们如何判断是否相交呢?

我们假设第一个区间就是一个集合,由于这个区间在前面,所以它就是第一个集合内最靠左的。因此,用这个区间的右端点和下一个区间的左端点做比较,如果相交了,那么就属于第一个集合,如果不相交,则结束当前集合,让那个未相交的区间成为一个新的集合。然后继续用新集合内的最靠左的区间的右端点继续去比较。

b、证明

反证法,假设存在一个最优解要比我们的算法算出来的结果还大。

那么由于这个不是我们的算法推出来的,只能说它选的不是集合内靠后的。

但是从图中可知,以集合1为例子,如果我们选了靠右的那个区间,很明显,这个区间覆盖了两个,结果是比我们算出来的结果少1的。

因此,假设不成立。

(3)代码

#include<iostream>
#include<algorithm>
using namespace std;
typedef pair<int,int> pii;
const int N=1e5+10;
int n;
pii a[N];
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        a[i].first=r,a[i].second=l;
    }
    sort(a,a+n);
    int ans=0,ed=-2e9;
    for(int i=0;i<n;i++)
    {
        if(ed<a[i].second)
        {
            ans++;
            ed=a[i].first;
        }
    }
    cout<<ans<<endl;
    return 0;
}

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

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

相关文章

Linux系统编程——基础篇

文章目录一、快捷键二、文件1.重要文件2.文件类型3.cp4.增加权限5.修改三、查找和检索四、安装五、压缩与解压六、vim的三种工作方式七、gcc编译四步骤八、静态库和动态库一、快捷键 Ctrla&#xff1a;光标移到开头 Ctrle&#xff1a;光标移到结尾 Ctrlu&#xff1a;清除整行 …

SQLSERVER 居然也能调 C# 代码 ?

一&#xff1a;背景 1. 讲故事 前些天看到一个奇怪的 Function 函数&#xff0c;调用的是 C# 链接库中的一个 UserLogin 方法&#xff0c;参考代码如下&#xff1a; CREATE FUNCTION dbo.clr_UserLogin (name AS NVARCHAR(100),password AS NVARCHAR(100) ) RETURNS INT AS…

Kali Linux中shutdown指令的用法3-1

在Kali Linux中&#xff0c;shutdown指令用于停止&#xff08;halt&#xff09;、关闭&#xff08;power off&#xff09;或者重启&#xff08;reboot&#xff09;系统。 1 语法格式 shutdown指令的语法如下所示 shutdown [OPTIONS] [TIME] [WALL] 其中&#xff0c;OPTIONS…

Qt、使用QToolButton和QStackedWidget的侧边栏(SideBar)的实现与实现原理解析

Qt、侧边栏&#xff08;SideBar&#xff09;的原理与实现&#xff08;附Demo&#xff09; 目录Qt、侧边栏&#xff08;SideBar&#xff09;的原理与实现&#xff08;附Demo&#xff09;1、简介2、侧边栏控件组成3、UI布局4、代码实现界面的切换Demo下载&#xff1a;https://git…

2023四川大学图书情报档案专业考研初试介绍(2023.1.02已更新)

文章目录川大图情基本情况2023年招生情况近5年录取数据复试2021-2022年复试线学硕复试线图情专硕复试线2021-2022年复试录取分数2022年学硕部分拟录取人员详细分数(不含调剂)专业课备考专业课资料博主所售资料一览667科目备考参考策略972科目备考方法参考目标分数川大图情基本情…

分享一套开源的springboot制造执行MES系统源码,带本地部署搭建教程+运行文档

全开源的一套超有价值的JAVA制造执行MES系统源码 亲测 带本地部署搭建教程 教你如何在本地运行运行起来。 开发环境&#xff1a;jdk1./1.8 tomcat mysql5.6springmvcmaven 需要源码学习&#xff0c;私信我获取。 一、系统概述&#xff1a; MES制造执行系统&#xff0c;其定位…

十分钟入门HBase特性与安装部署

1.写在前面 目前Hadoop生态的大数据组件都有一个其本身擅长的领域&#xff0c;并且目前看来&#xff0c;这个领域相对较窄&#xff0c;所以各位学生在大数据相关活动中&#xff0c;难免会有技术交集&#xff0c;最近学生在做离线数仓项目的时候&#xff0c;采用kylin技术组件&a…

【MySQL进阶教程】 存储引擎详细介绍

前言 本文为 【MySQL进阶教程】 存储引擎 相关知识介绍&#xff0c;下边具体将对MySQL体系结构&#xff0c;存储引擎介绍&#xff0c;存储引擎特点&#xff08;包含&#xff1a;InnoDB、MyISAM、Memory的特点及对比&#xff09;&#xff0c;存储引擎选择等进行详尽介绍~ &…

学习SpringCloudAlibaba(一)

一、为什么使用SpringCloud Alibaba 有了spring cloud这个微服务的框架&#xff0c;为什么又要使用spring cloud alibaba这个框架了&#xff1f; 最重要的原因在于spring cloud中的几乎所有的组件都使用Netflix公司的产品&#xff0c;然后在其基础上做了一层封装。然而Netfli…

走过 2022

“听过很多道理&#xff0c;依然过不好这一生”。每年写年终总结也是。但是审视自己在过去一年的表现依然是必需的。“吾日三省吾身”&#xff0c;更好的当然是每天都有所反思。世间很多事都离不开反馈&#xff0c;写总结就是一个很好的反馈。经历了过去荒诞的一年&#xff0c;…

开源虚拟机 qemu 安装以及使用方法 (helloos.img)

这篇文章里有 30Day Make OS 光盘的内容&#xff0c;感谢博主 https://blog.csdn.net/monster663/article/details/115919391 链接&#xff1a;https://pan.baidu.com/s/18dz8CuOxN21EAIU3os2KpA 提取码&#xff1a;qwer qemu 牛啤&#xff01; 从 https://www.qemu.org/down…

【阶段一】Python快速入门05篇:高级特性、pip工具、模块的使用、类(class)与异常处理

本篇的思维导图: 高级特性 列表生成式 现在有一个列表,你需要对该列表中的每个值求平方,然后将结果组成一个新列表。 描述 代码

分享101个PHP源码,总有一款适合您

链接&#xff1a;https://pan.baidu.com/s/1Jh2STRXhYU92KyGuaz_rsQ?pwdjvks 提取码&#xff1a;jvks PHP源码 分享101个PHP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c;大家下载…

VMware安装银河麒麟V10桌面版虚拟机

VMware安装银河麒麟V10桌面版虚拟机 第一章 VMware安装银河麒麟V10桌面版虚拟机 文章目录VMware安装银河麒麟V10桌面版虚拟机安装环境一、iso下载二、安装步骤1.创建虚拟机2.启动虚拟机&#xff0c;并安装操作系统安装环境 提示&#xff1a;虚拟机安装需要较大的磁盘空间&…

Java——使用多线程从list中不重复地取出数据并进行处理,给多线程任务添加单项任务计时和总耗时

Java——使用多线程从list中不重复地取出数据并进行处理&#xff0c;给多线程任务添加单项任务计时和总耗时一、最简版-无参数传递1.创建业务类&#xff0c;实现Runnable接口2.创建线程&#xff0c;实例化自己创建的业务类并调用3.运行结果二、加强版-有参数传递1.创建业务类&a…

第8季1:海思平台OSD的理论基础

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 一、OSD概述 1、区域管理模块 “OSD”是“on screen display”的缩写&#xff0c;即在屏幕上播放。 用户需要在视频中叠加OSD或者色块&#xff0c;来显示一些特定信息&#xff0c;比如通道号、时…

浅谈Java并发

Java并发是比较难的知识点&#xff0c;难于对并发的理解。并发要从操作系统和硬件层面去理解&#xff0c;才会比较深入&#xff0c;而不单单是从编程语言的逻辑去理解。 首先对于并发要清楚的几点&#xff1a; 线程可能在任何时刻被切换。 计算机只对硬件指令保证原子性。 CP…

关于一名资深Java程序员在移动端的进阶之路

目录 那年刚毕业 初识移动端 H5开始入门 微信小程序开发 未来的目标(唯有热爱&#xff0c;可抵这岁月漫长) 既然进来了&#xff0c;就帮我点亮五星好评吧&#xff0c;你的五星就是对我最大的支持和鼓励…… https://bbs.csdn.net/topics/611387335 今天呢&#xff0c;就借…

Prometheus配合 alertmanager 使用企业微信告警(坑已平!!!)

部署Prometheus 和 Alertmanager略 安装包部署prometheusGrafananode_exporter_争取不加班&#xff01;的博客-CSDN博客 prometheus监控报警部署Alertmanager_争取不加班&#xff01;的博客-CSDN博客 配置企业微信报警 首先使用企业微信创建一个企业 然后点击头像&#xff…

C++进阶 map和set

作者&#xff1a;小萌新 专栏&#xff1a;C进阶 作者简介&#xff1a;大二学生 希望能和大家一起进步&#xff01; 本篇博客简介&#xff1a;简单介绍C中map和set容器 map和set关联式容器树形结构与哈希结构键值对setset的介绍set的定义方式方式一&#xff1a; 构造一个某类型的…