Acwing 区间问题

news2024/12/23 14:16:42

Acwing 905.区间选点

在这里插入图片描述
实现思路:

  • 将每个区间按照右端点从小到大排序
  • 从前往后依次枚举每个区间
    • 若当前区间中已经包含点,则跳过;
    • 否则(即当前区间的左端点大于该点),选择当前区间的右端点;
  • 证明:比较最终结果ans和选出的点个数cnt大小关系,即证ans>=cnt&&cnt>=ans
    • 先证ans<=cnt:由于上述方法选择的方案保证了每一个区间都至少包含一个点,因此为一个合法的方案,而ans表示的是合法方案中的最少点个数,因此ans<=cnt。
    • 再证ans>=cnt:考虑没有被跳过的区间,区间互不相交,因此选中cnt个区间,要想覆盖所有区间,最终的答案一定至少为cnt个点(因为区间是独立的),即ans>=cnt。得证。

具体实现代码(详解版)

#include <iostream>
#include <algorithm>  

using namespace std;

const int N = 100010;  

int n;  
struct Range{
    int l, r;  // l 表示区间左端点, r 表示区间右端点
    // 重载小于运算符,用于将区间按照右端点 r 进行升序排序
    bool operator< (const Range &W) const
    {
        return r < W.r;  // 按右端点 r 从小到大排序
    }
} range[N];  // 定义一个大小为 N 的 Range 数组来存储区间

//自定义排序函数
// bool cmp(Range r1,Range r2){
//     return r1.r < r2.r;
// }

int main() {
    cin >> n;  
    
    for (int i = 0; i < n; i++) {
        int l, r;
        cin >> l >> r;
        range[i] = {l, r};  // 将左端点和右端点存入 range 数组
    }

    // 对区间按照右端点进行排序
    sort(range, range + n);
    
    //sort(range,range + n,cmp);

    int res = 0;          // 结果变量,记录需要选择的点的数量
    int ed = -2e9;        // 初始化已选点的右端点,设为一个很小的值,确保第一个区间被选中

    // 遍历所有区间
    for (int i = 0; i < n; i++) {
        // 如果当前区间的左端点大于上一个选中的点的右端点
        if (range[i].l > ed) {
            res++;             // 需要选择一个新的点
            ed = range[i].r;   // 更新已选点的右端点为当前区间的右端点
        }
    }

    cout << res << endl;  
    return 0;
}

注意:排序也可以自己写一个cmp函数,不用重载小于运算符(感觉不好记hhh)!

Acwing 908.最大不相交区间数量

在这里插入图片描述
实现思路:与上题思路一样,代码也一样
证明:比较最终结果ans和选出的区间个数cnt大小关系,即证ans>=cnt&&cnt>=ans。
先证ans>=cnt:由于选出的区间各不相交,因此为合法的方案,而ans为最大的一个,所以有ans>=cnt成立;
再证ans<=cnt:cnt表示每个区间都至少有一个选好的点,而ans表示表示所有不相交的区间的数量,说明至少应该有ans个点才能使得每一个区间都有一个点,所以ans<=cnt成立。

具体实现代码:

#include <iostream>
#include <algorithm>  

using namespace std;

const int N = 100010;  

int n;  
struct Range{
    int l, r;  // l 表示区间左端点, r 表示区间右端点
    // 重载小于运算符,用于将区间按照右端点 r 进行升序排序
    bool operator< (const Range &W) const
    {
        return r < W.r;  // 按右端点 r 从小到大排序
    }
} range[N];  // 定义一个大小为 N 的 Range 数组来存储区间

//自定义排序函数
// bool cmp(Range r1,Range r2){
//     return r1.r < r2.r;
// }

int main() {
    cin >> n;  
    
    for (int i = 0; i < n; i++) {
        int l, r;
        cin >> l >> r;
        range[i] = {l, r};  // 将左端点和右端点存入 range 数组
    }

    // 对区间按照右端点进行排序
    sort(range, range + n);
    
    //sort(range,range + n,cmp);

    int res = 0;          // 结果变量,记录需要选择的点的数量
    int ed = -2e9;        // 初始化已选点的右端点,设为一个很小的值,确保第一个区间被选中

    // 遍历所有区间
    for (int i = 0; i < n; i++) {
        // 如果当前区间的左端点大于上一个选中的点的右端点
        if (range[i].l > ed) {
            res++;             // 需要选择一个新的区间
            ed = range[i].r;   // 更新已选点的右端点为当前区间的右端点
        }
    }

    cout << res << endl;  
    return 0;
}

Acwing 906.区间分组

在这里插入图片描述
实现思路:

  • 将所有区间按照左端点从小到大排序;
  • 从前往后处理每个区间
    • 判断能否将当前区间放到某个现有的组中,判断现有的组中的最后一个区间的右端点(即最大右端点),是否小于当前区间的左端点
      • 若小于,则意味着该组存在一个区间与当前区间相交,则不能放到该组,需要重新开一个组;
      • 否则可以加入当前组(没有相交)
  • 使用小根堆来存储所有组的右端点,那么堆顶就是右端点最小的一个组,如果当前的左端点小于这个组的右端点,就表示当前区间与现有组产生相交,必然要开一个新的组即加入堆中。否则当前区间至少可以加入堆顶的那个组,更新一下右端点(就是删除堆顶元素,再添加)
  • 最后输出堆的大小即为最小组数。

具体实现代码(详解版):

#include <iostream>
#include <algorithm>  
#include <queue>
using namespace std;

const int N = 100010;  

int n;  
struct Range{
    int l, r;  // l 表示区间左端点, r 表示区间右端点
    // 重载小于运算符,用于将区间按照右端点 r 进行升序排序
    bool operator< (const Range &W) const
    {
        return l < W.l;  // 按右端点 r 从小到大排序
    }
} range[N];  // 定义一个大小为 N 的 Range 数组来存储区间

//自定义排序函数
// bool cmp(Range r1,Range r2){
//     return r1.r < r2.r;
// }

int main() {
    cin >> n;  
    
    for (int i = 0; i < n; i++) {
        int l, r;
        cin >> l >> r;
        range[i] = {l, r};  // 将左端点和右端点存入 range 数组
    }

    // 对区间按照左端点进行排序
    sort(range, range + n);
    //使用优先队列构造小根堆
    priority_queue<int ,vector<int>,greater<int> > heap;
    for(int i = 0 ; i < n ; i ++){
        if(heap.empty() || heap.top() >= range[i].l) heap.push(range[i].r);//新开一个组
        else{//否则可以加入堆顶的组,更新一下右端点
            heap.pop();
            heap.push(range[i].r);
        }
    }
    
    cout << heap.size() << endl;  
    return 0;
}

Acwing 907.区间覆盖

在这里插入图片描述
实现思路:
设线段的左端点为start,右端点为end

  • 所有区间按照左端点从小到大排序
  • 从前往后依次枚举每个区间,在所有能覆盖start的区间中,选择一个右端点最大的区间,随后,将start更新为选中区间的右端点。当start >= end,结束
  • 用双指针算法来找左端点<start,且右端点最大的区间,若找到的右端点依旧小于start,即无解;否则区间数量+1,且更新start
  • 注意:一轮过后i=j-1j是满足条件的区间,为了避免一些不必要的i枚举,所以i可以跳到满足条件的区间继续向后,但因为一轮后i++,所以先-1,下一轮就从j开始,这样又不会缺少或跳过满足的区间

具体实现代码(详解版):

#include <iostream>
#include <algorithm>  
#include <queue>
using namespace std;

const int N = 100010;  

int n;  

struct Range {
    int l, r;  // l 表示区间左端点, r 表示区间右端点
    // 重载小于运算符,用于将区间按照左端点 l 进行升序排序
    bool operator< (const Range &W) const {
        return l < W.l;  // 按左端点 l 从小到大排序
    }
} range[N];  // 定义一个大小为 N 的 Range 数组来存储区间

int main() {
    int start, end;
    cin >> start >> end;  
    cin >> n;  

   
    for (int i = 0; i < n; i++) {
        int l, r;
        cin >> l >> r;
        range[i] = {l, r};  // 将左端点和右端点存入 range 数组
    }

    // 对区间按照左端点 l 进行升序排序
    sort(range, range + n);

    int res = 0;          // 结果变量,记录需要选择的区间数量
    bool success = false; // 表示是否能够找到满足条件的解

    // 遍历每个区间
    for (int i = 0; i < n; i++) {
        int j = i, r = -2e9;  // r 用来记录当前覆盖的最大右端点
        // 寻找所有能够与当前 start 相交的区间
        while (j < n && range[j].l <= start) {
            r = max(r, range[j].r);  // 更新能覆盖的最远右端点
            j++;  // 继续往后找
        }

        // 如果找不到一个右端点能够覆盖当前 start,说明无解
        if (r < start) break;

        // 找到一个合适的区间,区间数量加 1
        res++;

        // 如果右端点已经能够覆盖到 end,说明找到了解
        if (r >= end) {
            success = true;
            break;
        }

        // 更新新的起点为当前找到的最远右端点,继续寻找下一个区间
        start = r;
        i = j - 1;  // 更新 i 的位置
    }

    cout << (success ? res : -1) << endl;

    return 0;
}

以上就是几个经典的区间问题,重点在于思路的证明(不行就试)

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

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

相关文章

设计模式:单例

一.什么是单例模式 单例模式是一种设计模式&#xff0c;指在整个程序生命周期中有且仅有一个实例的类。可以分为懒汉式以及饿汉式。 懒汉式&#xff1a;只有在类的实例被使用时才生成唯一实例。但是存在线程安全以及内存泄露的问题。可以节省系统资源。 饿汉式&#xff1a;程序…

《Oracle DB备份与恢复》:一文千字教你掌握备份基础知识

** List item 备份需要扎实掌握基础知识&#xff0c;这样才能规划好适合自己的备份恢复策略&#xff0c;才能在出故障的时候不慌不忙&#xff0c;从容应付。 好了不多逼逼了&#xff0c;直接上干货。** 1. 备份分类&#xff1a; 备份根据性质和目的不同分为以下几种&#…

车辆路径规划问题(VRP)优化方案

车辆路径规划问题&#xff08;VRP&#xff09;优化方案 车辆路径规划问题&#xff08;Vehicle Routing Problem, VRP&#xff09;是物流领域中一个经典的组合优化问题&#xff0c;目标是在满足客户需求的情况下&#xff0c;找到一组车辆的最优配送路径&#xff0c;以最小化总的…

如何让员工意识到六西格玛项目对公司和个人的长期利益?

当下&#xff0c;六西格玛作为一种以数据驱动的管理方法论&#xff0c;正逐步成为许多企业实现卓越运营的重要工具。然而&#xff0c;要让员工深刻认识到六西格玛项目不仅对公司长远发展至关重要&#xff0c;也对他们个人职业生涯有着深远的积极影响&#xff0c;并非易事。下面…

C++ day05(模版与容器)

目录 【1】模版 template 1》概念 2》函数模版 3》类模版 【2】容器 1》STL标准模版库 2》容器的概念 3》顺序容器 1> arrry(C11) 2> vector 3> list 4> deque 4》 关联容器 5》迭代器 iterator 【1】模版 template 1》概念 C模版可以让类或函数声…

javacpp调用pdfium的c++动态库

1、.h头文件 2、生成java代码的conf PdfiumDocumentConfigure.java package org.swdc.pdfium.conf;import org.bytedeco.javacpp.annotation.Platform; import org.bytedeco.javacpp.annotation.Properties; import org.bytedeco.javacpp.tools.InfoMap; import org.byte…

网络知识点之—EVPN

EVPN&#xff08;Ethernet Virtual Private Network&#xff09;是下一代全业务承载的VPN解决方案。EVPN统一了各种VPN业务的控制面&#xff0c;利用BGP扩展协议来传递二层或三层的可达性信息&#xff0c;实现了转发面和控制面的分离。 EVPN解决传统L2VPN的无法实现负载分担、…

springboot+vue前后端分离-使用腾讯云服务器部署网站

项目打包 参考链接 CSDN springboot打包 idea默认新建的shell窗口在项目根目录位置&#xff0c;可以看到项目根目录下有mvnw HELP.md log mvnw mvnw.cmd pom.xml src target./mvnw clean package -Dmaven.test…

Kali Linux中安装配置影音资源下载神器Amule

一、Debian系列Linux安装amule命令&#xff1a; sudo apt update sudo apt-get install amule amule-utils 二、配置Amule的要点&#xff1a; 1、首次运行Amule&#xff0c;提示是否下载服务器列表&#xff0c;点击是。 2、搜索选项的类型选择全球&#xff0c;类型的默认选项…

数据恢复与数据取证:Visual NAND Reconstructor 闪存数据恢复工具

天津鸿萌科贸发展有限公司是专业闪存数据恢复工具 VNR (Visual NAND Reconstructor) 的授权代理商。 VNR&#xff08;Visual NAND Reconstructor&#xff09;可视化 NAND 重建工具套件由硬件和软件构成。其中硬件部分包含 NAND 读卡器和一组用于不同 NAND 芯片封装的适配器。读…

LeetCode 48 Rotate Image 解题思路和python代码

题目&#xff1a; You are given an n x n 2D matrix representing an image, rotate the image by 90 degrees (clockwise). You have to rotate the image in-place, which means you have to modify the input 2D matrix directly. DO NOT allocate another 2D matrix and …

序列化流和反序列化流

序列化流 ObjectOutputStream 序列化流/对象操作输出流 包装基本流&#xff0c;属于字节流的一种&#xff0c;负责输出数据。可以把Java中的对象写到本地文件中去。 构造方法&#xff1a; public ObjectOutputStream&#xff08;OutputStream out&#xff09;把基本流包装成高…

【Java 并发编程】解决多线程中数据错乱问题

前言 承接上回&#xff0c;我们已经理解了线程的一些相关操作&#xff0c;本篇内容将会讲到如何去解决线程竞争导致的数据错乱。 前期回顾&#xff1a;线程操作 目录 前言 线程竞争的场景 竞态条件的详解 synchronized 关键字 ReentrantLock 类 线程竞争的场景 概念&#xff1a…

异步场景: promise、async函数与await命令介绍

如果你也对鸿蒙开发感兴趣&#xff0c;加入“Harmony自习室”吧&#xff01;扫描下方名片&#xff0c;关注公众号&#xff0c;公众号更新更快&#xff0c;同时也有更多学习资料和技术讨论群。 在鸿蒙的开发中&#xff0c;我们时常会遇到promise异步场景&#xff0c;有同学反馈说…

Adobe Acrobat Pro和Adobe Acrobat DC有什么区别?

主要区别 Adobe Acrobat Pro&#xff1a; 以单次购买的方式提供&#xff0c;用户需要一次性付费购买&#xff0c;之后即可永久使用该版本。不会频繁更新&#xff0c;通常只在发行新版本时进行更新。 Adobe Acrobat DC&#xff1a; 以订阅方式提供&#xff0c;用户需要每年支付…

《2024 国庆旅游数据洞察:活力与新趋势》

《2024 国庆旅游数据洞察&#xff1a;活力与新趋势》 一、国庆旅游市场整体态势 今年国庆假期&#xff0c;旅游市场的火爆程度令人瞩目。从出行人次来看&#xff0c;嘀嗒出行的国庆顺风出行预测显示&#xff0c;顺风出发高峰日预计为 9 月 29 日&#xff0c;环比 9 月出行峰值…

在Ubuntu 22.04上安装Ollama的两种方式

curl 安装 参考Linux上安装Ollama的官方文档&#xff1a;https://ollama.com/download/linux 在终端执行以下命令即可&#xff1a; curl -fsSL https://ollama.com/install.sh | shdocker 安装 官方 Ollama Docker 镜像可以直接在Docker Hub上进行拉取。 Docker Hub上的ol…

Java 方法的重载

1.重载&#xff1a;在一个类中&#xff0c;方法的函数名相同&#xff0c;但形参不同。 结果&#xff1a; 2&#xff0e;方法重载的规则&#xff1a; &#xff08;1&#xff09;方法名必须相同。&#xff08;例如&#xff1a;重名的人有很多&#xff09; &#xff08;2&#x…

数据库(MySQL):使用命令从零开始在Navicat创建一个数据库及其数据表(二).设置主键自增等特点

前言 在上一节中&#xff0c;主要介绍了 Navicat Premium 17 的使用以及创建一个基础的表格。当时只设置了给数据表补充字段&#xff0c;没有设置给数据表删除字段。现在补充一下。 ALTER TABLE student ADD test int(4); 给名为 student 的数据表添加 test 列&#xf…

正则表达式-“三剑客”(grep、sed、awk)

1.3正则表达式 正则表达式描述了一种字符串匹配的模式&#xff0c;可以用来检查一个串是否含有某种子串&#xff0c;将匹配的子串替换或者从某个串中取出符号某个条件的子串等&#xff0c;在linux中代表自定义的模式模版&#xff0c;linux工具可以用正则表达式过滤文本。Linux…