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

news2024/11/16 12:08:34

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

  • 一、什么贪心策略?
  • 二、区间问题合集
    • 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/134284.html

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

相关文章

java:文件分片上传

代码下载地址&#xff1a;https://download.csdn.net/download/u013938578/87358484 1 文件上传、断点续传服务端 1.1 新建maven项目 文件结构如下&#xff1a; 1.2 引入百度开源上传组件webuploader 1.3 前端页面upload.html <!DOCTYPE html> <html lang"en&…

Java个人家乡博客源码

概述 个人博客相册家乡主题&#xff0c;用户注册后可以发布关于家乡的特色文章介绍&#xff0c;可以发布照片&#xff0c;相册管理&#xff0c;留言&#xff0c;评论&#xff0c;回复&#xff0c;收藏&#xff0c;关注 演示视频 https://www.bilibili.com/video/BV1iy4y1x7w6…

SSM框架-注解开发

11 注解开发 11.1 注解开发定义Bean 代码 接口BookDao public interface BookDao {void save(); }实现类BookDaoImpl【更改之处】 在最上面Component(“bookDao”) Component("bookDao") //或者Repository("bookDao") public class BookDaoImpl impl…

【C++】-- 哈希(上万字详细配图配代码从执行一步步讲解)

目录 哈希 常见哈希函数 除留余数法 哈希冲突 哈希冲突解决 闭散列 a、线性探测 插入 查找 删除 线性探测的实现代码 b、二次探测 二次探测的实现 开散列 开散列实现 插入 查找 删除 析构函数 代码汇总 哈希 常见哈希函数 直接定址法 -- (常用)-- 不存在哈…

2022 年博客总结

时间过的飞快&#xff0c;孩子也快4岁了&#xff0c;1号带孩子去玩雪&#xff0c;发生了一件有趣的事&#xff0c;发个视频。 带孩子玩雪我拉着闺女&#xff0c;闺女拉着儿子&#xff0c;忽略了力的作用&#xff0c;我以为只有我在使劲&#xff0c;实际上闺女需要需要更大的力拉…

java8新特性——函数式编程

文章目录1.函数式编程思想1.1概念1.2函数式编程的思想2.Lambda表达式2.1概述2.2核心原则2.3基本格式2.4Lambda表达式练习2.5省略规则3.Stream流3.1概述3.2案例准备3.3Steam流操作案例3.3.1需求3.3.2实现3.4Stream常用操作3.4.1创建stream流方式3.4.2中间操作3.4.2.1filter3.4.2…

SpringMVC 底层机制的简易实现

SpringMVC 底层机制的简易实现项目基础配置 xml 文件开发指南开发步骤1.初始化数据2.中央控制器 - 分发请求3.开发者角度4.视图解析器开发总结项目基础 <dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId&g…

【Python基础】常用数据结构及处理

1. KeyValue dict.clear() 删除字典内所有元素dict.copy()返回一个字典的浅复制[dict.fromkeys(seq, val])创建一个新字典&#xff0c;以序列 seq 中元素做字典的键&#xff0c;val 为字典所有键对应的初始值 dict.get(key, defaultNone) 返回指定键的值&#xff0c;如果值不在…

prompt模型详解之文本生成

prompt在生成方面的应用从两个方面进行介绍&#xff1a; 评估手段 具体任务 评估手段 生成任务的评估手段主要分为四种类型&#xff1a; 1). 基于N-gram匹配 2). 基于编辑距离 3). 基于词向量 4). 基于可学习方式。 本小节主要介绍BARTSCORE&#xff0c;其使用prompt方…

Python杂题

目录 一、前言 二、例题1——修剪灌木 三、例题2—— 付账问题 四、例题3——最少砝码 五、例题四——矩形拼接 六、例题五——蜂巢 一、前言 竞赛题有很多不需要什么算法的题目&#xff0c;只要学过编程语言就能做&#xff0c;其考核思维、逻辑、编码能力。而这种题有“…

【算法题解】 8. K 个一组翻转链表

文章目录题目解题思路代码实现复杂度分析题目 给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保持…

Python中编码(encode)解码(decode)讲解

嗨害大家好鸭&#xff01;我是小熊猫~ 这次也是给大家带来一点干货~ 所用素材:点击此处跳转文末名片获取 一、python3中str与unicode 在python3中&#xff0c;字符串有两种形式&#xff1a;str和bytes&#xff0c;两者区别如下&#xff1a; unicode string(str类型)&#xf…

【经验】关于区分cin、getline、cin.getline三种字符串输入的区别

cin 既可以输入char[]数组&#xff0c;也可以输入string类型&#xff0c;输入会被空格打断 cin对char进行输入 #include<bits/stdc.h> using namespace std; int main(){char ch[50];cin>>ch;cout<<strlen(ch)<<endl;for(int i0;i<strlen(ch);i){…

1.移动机器人发展现状

移动机器人主要应用场景&#xff1a; 场景1.仓储机器人(AGV自动导引运输车)&#xff1a;电商企业用户下单后机器人可以实现自动分拣和发货。需要多个传感器配合 2.自动驾驶领域(AMR自主移动机器人):车辆避让行人、导航等 热点研究领域&#xff1a; 环境感知和建模、人机交互…

2022简要总结和2023行动指南

在这辞旧迎接之际&#xff0c;心存感恩&#xff0c;放眼未来。 祝宝妈妈宝&#xff0c;幸福快乐&#xff1b; 祝国泰民安&#xff0c;政通人和。 祝百融云创系&#xff0c;生意兴隆&#xff1b; 祝公司老板们&#xff0c;大展宏图&#xff1b; 祝同事同行er&#xff0c;身…

Java算法_LeetCode:旋转数组

旋转数组 给你一个数组&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4,5] 向右轮转 3 步: [5,6,7,1,2,3,…

Fastsapi的小疑问

1. Fastapi中的get和post区别是什么&#xff1f; 答&#xff1a;get参数传输暴露在外&#xff0c;post隐式传输 GET参数获取&#xff1a;获取一个URL后面带?param11&param22这种形式。 特点&#xff1a;URL上直接编辑传输&#xff0c;方便快捷&#xff0c;但是信息暴露在…

【nowcoder】笔试强训Day16

目录 一、选择题 二、编程题 2.1扑克牌大小 2.2完全数计算 一、选择题 1.在关系型是数据库中&#xff0c;有两个不同的事务同时操作数据库中同一表的同一行&#xff0c;不会引起冲突的是&#xff1a; A. 其中一个DELETE操作&#xff0c;一个是SELECT操作 B. 其中两个都是…

植物大战僵尸:代码实现无限阳光

通过逆向分析植物阳光数量的动态地址找到阳光的基址与偏移&#xff0c;从而实现每次启动游戏都能够使用基址加偏移的方式定位阳光数据&#xff0c;最后我们将通过使用C语言编写通用辅助实现简单的无限阳光辅助&#xff0c;在教程开始之前我们先来说一下为什么会有动态地址与基址…

光缆单盘检测与光缆线路测试需使用双窗口吗?

1 引言 光缆线路和宽带接入工程中&#xff0c;通常会涉及光缆单盘检测与光缆线路的测试工作&#xff0c;光缆线路测试包括&#xff1a;中继段测试、用户光缆测试等。这些测试条目&#xff0c;有的只需采用测试仪表的1个波长进行测试&#xff0c;即单窗口测试&#xff0c;有的则…