区间相关问题的学习: 最多不相交区间问题,区间选点问题与区间覆盖问题

贪心—最大区间不相交问题 (加强版) 弱版:https://blog.youkuaiyun.com/yanzhenhuai/article/details/81111598 让我们继续来思考这样的一个问题 : 给出n条区间的起点和终点(输入保证所有区间都是起点<终点),每一局可以选出若干个之前没有选出的区间,这些区间满足两两无交集(可以某区间的终点与另一区间的起点相同)。 问最少多少局可以选出所有的区间。 ... 阅读详情

区间相关问题包括: 1)最多不相交区间问题; 2)区间选点问题; 3)区间覆盖问题等。

最多不相交区间问题(又叫选择不相交区间,最大不相交覆盖等等),是指数轴上有n个开区间(a,b),选择尽量多个区间,使得这些区间两两没有公共点。

注意:
1)该问题也适用于闭区间[a,b],不过要加一条:如果一个区间的右端点和另一个区间的左端点重合,视为不相交。

思路: 贪婪法。首先将n个区间按右端点b 升序排序,先选择右端点最小的那个区间,这里如果有多个区间的右端点重合,则选择左端点最大的那个 (保证所选区间块头最小)。然后从左到右,选择第一个不与该区间相交的那个区间,依次扫描一遍数组即可。所以复杂度就是排序的复杂度O(nlogn)。

打印区间的时候用了一个变量overlapping,以保证一个区间不会被打印多次。

代码如下。选择区间为(2,6),(1,,4),(3,6),(2,4),(6,8),(2,4),(3,5)。注意第一个区间应该选(2,4)而不是(1,4)。另外(2,4)出现了2次,maxRegionNonOverlap()的else分支里面把第二个(2,4)skip了。

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

struct Region {
   int left;
   int right;
   Region(int x, int y): left(x), right(y) {}
   Region() {}
   bool operator < (const Region &r) const {
       return right < r.right;
   }
};

void print_region(Region &r) {
    cout<<"("<<r.left<<", "<<r.right<<")";
}

int maxRegionNonOverlap(vector<Region>& a) {
    int num = 1;
    sort(a.begin(), a.end());

    int save_index = 0;
    bool overlapping = false;
    for (int i=1; i<a.size(); i++){
        if (a[i].right > a[save_index].right) {
            if ((a[i].left <= a[save_index].right) && !overlapping) {  //overlap with the previous saved case.
                print_region(a[save_index]);
                overlapping = true;
            }

            if (a[i].left >= a[save_index].right) { //two ranges not overlap, good case.
                num++;
                print_region(a[i]);
                save_index = i;
                overlapping = false;
            }
        }
        else { //right border the same
            if (a[i].left > a[save_index].left) { //left border different
                save_index = i;
            }
        }

    }

    return num;
}


int main()
{
    vector<Region> region;

    region.push_back(Region(2,6));
    region.push_back(Region(1,4));
    region.push_back(Region(3,6));
    region.push_back(Region(2,4));
    region.push_back(Region(6,8));
    region.push_back(Region(2,4));
    region.push_back(Region(3,5));

    cout<<"original list"<<endl;
    for_each(region.begin(), region.end(), print_region);
    cout<<endl;

    cout<<maxRegionNonOverlap(region);

    return 0;
}

上面的解法是参考的算法竞赛入门经典(第2版),我在网上看到的所有的讨论也是基于类似的方法。但我们再思考一下,可不可以按左端点排序,然后从最右边的端点往左遍历呢?这两种方法我觉得是等价的,因为最后两种方法都归结到a1<=a2<=…<=an, b1<=b2<=…<=bn (ai, bi分别为区间i的左右端点),所以它们得到的最优解是一样多的。不过,这两种方法所选的区间则不一定相同。

区间选点问题是说数轴上有n个闭区间[ai, bi]。取尽量小的点,使得每个区间内都至少有一个点(不同区间内含的点可以是同一个)。

该题与最多不相交区间问题类似,也是贪婪法把所有区间按b从小到大排序(若b相同,则a从大到小排序)。如果区间重合,则大区间不予考虑,因为小区间包含的点大区间都包含。从最左边的区间开始,取其右端点与右边的区间一一比较:
1)如果小于后面区间的左端点,则取该后面的右端点再与更后面的区间一一比较。
2)如果大于后面区间的左端点,则说明该右端点也在后面区间内部 (因为按b排序), 什么都不用做。
3) 如果等于后面区间的左端点,也什么都不用做。

代码如下:

int selectPoints(vector<Region> &a) {

    sort(a.begin(), a.end());
    int num = 0;
    int loc = -INT_MAX;
    for (int i=0; i<a.size(); i++) {
        if (loc < a[i].left) {
            loc = a[i].right;
            cout<<"location is "<<loc<<endl;
            num++;
        }
    }

    return num;

}

区间覆盖问题是指:数轴上有n个闭区间[ai,bi],选择尽量少的区间覆盖一条指定线段[s,t]。
思路也是贪婪法。把左端点ai从小到大排序,然后从左端点s开始,选择覆盖s的区间里面的右端点最长的那个。然后取该区间的右端点,继续往右扫描,重复上述步骤,直到到达右端点t。注意这里跟最多不相交区间不一样,我们按ai排序后,不是从最右端的区间开始往左扫描,而是从最左端区间的左端点s开始,选择覆盖s的最长的那个,然后取其右端点,继续往右扫描。

代码如下:

#include <iostream>
#include <algorithm>
#include <vector>
#include <climits>

using namespace std;

struct Region {
   int left;
   int right;
   Region(int x, int y): left(x), right(y) {}
   Region() {}
   bool operator < (const Region &r) const {
       return left < r.left;
   }
   bool operator != (const Region &r) const {
       return (left != r.left) || (right != r.right);
   }
};

void print_region(Region &r) {
    cout<<"("<<r.left<<", "<<r.right<<")"<<endl;
}

inline inRange(int x, Region r) {
    return (x>=r.left) && (x<=r.right);

}

int minRegionOverlapping(vector<Region>& a, int s, int t) {
    int num = 0;
    int loc = s;
    vector<Region> new_a;

    sort(a.begin(), a.end());

    //pre-processing
    for (vector<Region>::iterator iter=a.begin(); iter!=a.end(); iter++) {
        if ((iter->left >= s) && (iter->right <= t)) {
            new_a.push_back(*iter);
        }
        else if ((iter->left <=s) && (iter->right >= t)) {
            // 1 range is enough
            print_region(*iter);
            return 1;
        }
        else if ((iter->left <= s) && (iter->right >= s)) {
              new_a.push_back(*iter);
        }
        else if ((iter->left <= t) && (iter->right >= t)) {
              new_a.push_back(*iter);
        }
    }

    if (!new_a.size()) {
        cout<<"No solution!"<<endl;
        return 0;
    }

    sort(new_a.begin(), new_a.end());

    loc = s; //start from the left border of the line
    int new_loc = -INT_MAX;
    Region save_region = new_a[0];

    for (vector<Region>::iterator iter=new_a.begin(); iter!=new_a.end(); iter++) {
        if (inRange(loc, *iter) && (new_loc < iter->right)){
            new_loc = iter->right; //multiple ranges cover the loc, choose the one whose right-border is the furtherest
            save_region = *iter;
        }
        else if (!inRange(loc, *iter)) {
            if (inRange(new_loc, *iter)) { //it is time to determine the next loc
                num++;
                print_region(save_region);
                loc = new_loc;
                if (inRange(t, *iter)) {  //reach the end
                    num++;
                    print_region(*iter);
                    return num;
                }
            }
            else {
                cout<<"No solution!"<<endl;
                return 0;
            }
        }
    }
    return num;
}

int main()
{
    vector<Region> region;

    region.push_back(Region(2,6));
    region.push_back(Region(1,4));
    region.push_back(Region(3,6));
    region.push_back(Region(2,4));
    region.push_back(Region(5,8));
    region.push_back(Region(2,4));
    region.push_back(Region(3,5));

    cout<<"original list"<<endl;
    for_each(region.begin(), region.end(), print_region);
    cout<<endl;

    cout<<minRegionOverlapping(region, 6, 9);
    return 0;
}

一点总结:
这三种区间相关问题给出的解法中,最多不相交区间问题和区间选点问题按右端点排序,从左到右扫描,区间覆盖问题按左端点排序,从左到右扫描。

我们来归纳一下,什么样的问题就按左端点排序,什么样的问题就按右端点排序呢?其实根据对称性,这三个问题不管是根据左端点排序还是右端点排序都是可以的。但是因为最多不相交区间问题和区间选点问题是要选择尽量小的区间,所以如果它们是按右端点排序的话,就要从最左边的端点开始找,反之如果我们按左端点排序的话,就要从最右边的端点开始找。

为什么呢?我们可以这么来看:
按右端点排序后右b1<=b2<=…<=bn,
如果a1>a2, 则区间1包含在区间2内,区间1不能要。所以我们一开始一定是选ai里面最小的那个,也就是从最左边的端点开始选。
按左端点排序的情形也是类似的,在此不再赘述。

而对于区间覆盖问题,我们要选择尽量大的区间。如果我们按左端点排序后a1<=a2<=…<=an,
假设a1, a2, a3都覆盖起始点s,则显然要选bi最大的那个。如果我们从最右端点开始扫描则无法知道哪个会覆盖起始点s。所以只能从最左端开始扫描,并选覆盖起始点s的端点中bi最大的那个。
同样,该题也可以按右端点排序,然后选择所有包含t的区间中左端点最长的那个,然后从右向左扫描。

如果本文内容有任何不当之处,欢迎指正。

(SCADA)监控与数据采集系统 SCADA应用于监控和采集数据来控制工业过程软件。它通过收集和传输实时数据,帮助操作员监视和控制各种设备和过程。 阅读详情

相关推荐

软件测试方法——等价类划分法详解

!如果下面这些资料用得到的话可以直接拿走:1、自学开发或者测试必备的完整项目源码与环境2、测试工作中所有模板(测试计划、测试用例、测试报告等)3、软件测试经典面试题4、Python/Java自动化测试实战.pdf5、Jmeter/postman接口测试全套视频获取6、Python学习路线图。

MXB1220的博客 1万+

C++算法入门练习——区间不相交问题、区间选点问题

而对于区间选点问题,我们只需要在区间不相交问题中,小小修改,修改纳入区间条件:if(num[i].left>=num[templeft].right),只需要把等号去掉。理由是,我们每次取区间的左端点作为选取的点,这样就可以小区间内的点也覆盖了大区间内的点。然后取第一个的作为第一个取的区间,然后比较剩余区间里的,如果有其中的一个左端点大于等于已去区间的右端点,那么就应该纳入,这样就可以不相交。利用贪心思想,先将这些区间排序,按右端点最大的优先来排序,如果右端点相同,那么取左端点小的,这样区间短。

u011708235的博客 401

AMD锐龙笔记本隐藏玩法:分核降压+ PBO2超频全攻略(以5900HX/6900HX为例)

本文详细解析了AMD锐龙笔记本(以5900HX/6900HX为例)的分核降压与PBO2超频技术,帮助用户释放处理器隐藏性能。通过BIOS设置、Curve Optimizer参数调整及稳定性测试,实现性能提升与温度控制的完美平衡,适合硬件爱好者进阶调校。

weixin_30617737的博客 347

HDU 4293 Groups(区间dp)

HDU 4293 题意:有 n 个人,可任意分成若干组,然后每个人各提供一个信息,表示他们组前面有多少个人,后面有多少个人。问最多有多少个信息是真实的的。 思路: 这道题一开始给我的印象是什么乱七八糟的东西,后来也没想通到底该怎么做,好在赛后百度在手天下我有:) 我们可以把 这n个人看成一段区间 [1,n]。 设每个人的信息是a、b,则这个信息代表了他们组所在的区间 [a+1,n-b]。

a novice 853

Win本地部署DeepSeek

Ollama 提供了简单的接口,用于创建、运行和管理这些模型,同时还维护了一个丰富的预构建模型库,可以轻松集成到各种应用程序中。重启ollama,具体操作为打开搜索ollama进程,将其结束进程,之后再执行相关模型下载命令即可,或重启电脑!Ollama支持多种DeepSeek模型版本,用户可以根据硬件配置选择合适的模型。配置添加系统环境变量OLLAMA_MODELS,设置其值为新的路径,点击确定应用。安装完成后,在终端输入以下命令,检查Ollama版本。:14B、32B或70B版本,适合高端GPU。

m0_67297673的博客 2392

Ubuntu开发环境配置——持续更新

本文简要介绍了Ubuntu下的开发环境配置流程和问题分析与解决,更多内容持续更新中。

m0_53365889的博客 2225

贪心——区间覆盖问题之最大不相交覆盖问题

最大不相交覆盖问题:问题描述: 给定一个长度为m的区间,再给出n条区间的起点和终点,问题是从中选取尽量多的区间,使得每个区间都是独立的,即不和其它任何区间相交。方法 先将n个区间按照右端点进行递增排序。 令e为覆盖的右端点,初始化e为-1,然后对之后的区间进行判断选择,如果剩下区间的左端点大于e,那么就把此区间添加进去。 经典问题:会场安排问题 问题描述 学校的小礼堂每天都会有许多活动

karry_zzj的博客 2654

21天教你学会PCIe专栏(21)--总结和展望

回顾整个课程的主要内容和知识点总结PCIe技术的发展历程和现状展望PCIe技术的未来发展趋势和应用方向分享学习心得和实践经验1.1 课程回顾基础知识:了解了PCIe的基本概念、发展历程、标准和规范。分层结构:学习了PCIe的物理层、数据链路层和事务层的结构和功能。功能和特性:掌握了PCIe的热插拔、电源管理、多功能设备等高级功能。高速接口技术:学习了PCIe 4.0、5.0和未来趋势。实际案例分析:分析了GPU加速器和存储设备的PCIe设计和优化。常见问题和解决方案。

xiaoheshang_123的博客 673

区间贪心:区间不相交问题和区间选点问题

贪心算法 目的:求解一类问题的最优解或较优解 解释:将一个问题分成几个局部,解决问题时总是考虑局部最优(或较优)解,这种情况下得到的结果也是最优(或较优)的 注意:我们再看贪心算法解决的一道题时可能会发现,贪心算法有很多“不一定”,“不一定”得到的就是最优解,贪心算法并不强求得到最优解,得到较优解也可以 区间贪心:区间不交集问题 题目 给出N个开区间(x,y),从总选择尽可能多的区间,使这些开区间...

小枫哥的博客 1472

机器人环境仿真软件:Webots_(9).路径规划与导航算法仿真实现

通过仿真,我们可以验证路径规划算法的有效性和鲁棒性,同时优化机器人在不同环境中的导航性能。动态窗口法是一种局部路径规划算法,通过在机器人当前速度空间中选择一个最优的速度窗口,使机器人在动态环境中安全地移动。算法的代价函数通常包括两个部分:从起始点到当前节点的实际代价(g-cost)和从当前节点到目标节点的估计代价(h-cost)。在World Editor中,选择“Insert”菜单,添加“Robot”对象,如“E-puck”或“Thymio”。Dijkstra算法的实现与A*算法类似,但不使用启发函数。

kkchenjj的博客 2006

完整的 Python 数据分析案例:新能源汽车续航里程预测

随着新能源汽车的普及,续航里程成为消费者关注的重要指标。准确预测新能源汽车的续航里程,有助于车企优化电池管理系统、提升车辆性能,也能帮助消费者合理规划出行。本案例将基于新能源汽车的各项参数,如电池容量、行驶速度、环境温度等,构建续航里程预测模型。通过以上改进,可以提高数据处理的准确性、模型的性能和可视化的效果。

daqsdfas的博客 1588

贪心算法解决区间问题:合并、选点、覆盖、最大不相交

区间问题是贪心算法中的高频考点,而贪心算法是解决这类问题的 “黄金搭档”。本文将系统讲解基于贪心算法的四类经典区间问题:区间合并、区间选点、区间覆盖、最大不相交区间数量,帮助你彻底掌握这类问题的解题思路。

yyyyy_1111222的博客 530

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

区间相关问题的整理

区间相关问题的整理 掌握这些类型的区间问题,并且熟练掌握,就可以解决部分区间问题,当然不是全部,hhh,在这里我整理了一下相关区间问题的模板题,因为目前刷的题目还比较少,如果后续遇到其他类型的区间题目,也会更新!如果有存在问题希望大家能够指出。 类型: 1)最少点覆盖所有区间问题(区间选点) 2)选取不相交区间最大数量(最大不想交区间数量) 3)组内区间两两不相交的最小组数(区间分组) 4)选择最少区间覆盖线段区间(区间覆盖) 1)最少点覆盖所有区间问题(区间选点) 模板题目 给定 N 个闭区间 [ai,

Bananaaay的博客 1656

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

洛谷1803 贪心选择不相交区间模板题目,区间选点模板

选择不相交区间:数轴上有n个开区间(ai,bi),选择尽量多个区间,使得这些区间两两没用公共点 分析:若区间x包含y,那么选x比如选y划算,可以将y排除在外 区间排序成b1<=b2<=b3<=.......考虑a1,a2大小 情况1:a1>ai,只要后面存在ai使得a1>ai,则(ai,bi)不予考虑 情况2:a1<=a2<=a3<=....,若两区间不相交,则都可以选取,若是相交则只能选择一个,我们一定要选择(a1,b1)这样可以为后面留出最大的空间,

qq_62069884的博客 440

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

区间相关问题

此类问题区间有左右两个端点 , 非常适合用 pair 容器, 选择不相关区间 选择最多不相关区间数 , 按右端点排序 相同在按左端点排序(从小到大), 选择第一个区间后,排除相关区间, 再重复选符合的第一个,直到不能选择 例 http://nyoj.top/problem/14 #include<iostream>//http://nyoj.top...

diange5436的博客 305

贪心法之区间相关问题

/* author:杨汝生 time:2014-9-12,16:48 algorithm: 贪心法 */ #include #include #include struct Interval { int start; int finally; }intervals[100]; int cmp(const void *a,const void *b) { struct Interval

Magic Hacker 算法学习总结 408

区间问题解法(贪心)

labuladong之贪心算法区间调度 关于区间相关这类问题,基本思路都是排序,然后找交集或者找合集。首先要做的是讨论区间之间的包含情况,都画出图,决定是end还是start排序。 文章目录1. 最多不相交区间【题目描述】终点排序起点和终点排序的不同之处起点排序【例题】2.区间选点【题目描述】终点排序起点排序3.区间覆盖【问题描述】起点排序 1. 最多不相交区间 【题目描述】 n个开区间(ai,bi)(a_i,b_i)(ai​,bi​)。选择尽量多个区间,使得这些区间两两不相交。 终点排序 按照终点从小到

qq_37357873的博客 449

B001 排序贪心 最大不相交区间数 区间选点

最大不相交区间数这两类问题的关键都是后进行处理。

llq25801的博客 283

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

详解贪心策略中的区间问题的思路,代码和证明。

Turing_Sheep的博客 1935

区间相关问题总结

一、选择不相交区间 数轴上有n个区间[ai,bi],要求选择尽量多个区间,使得这些区间两两没有公共点 贪心策略: 按照b1 证明: 我们对a1,a2……的关系分以下几种情况考虑: 1、a1>a2。   此时区间2包含区间1。这种情况下显然不会选择区间2,因为选择区间1会留下更多的剩余空间。                       不仅区间2如此,以后所有区间中只要有一个 i

zxiaopp的专栏 2084

区间问题

区间相关问题包括: 1)最多不相交区间问题; 2)区间选点问题; 3)区间覆盖问题等。 最多不相交区间问题(又叫选择不相交区间,最大不相交覆盖等等),是指数轴上有n个开区间(a,b),选择尽量多个区间,使得这些区间两两没有公共点。 注意:  1)该问题也适用于闭区间[a,b],不过要加一条:如果一个区间的右端点和另一个区间的左端点重合,视为不相交。 思路: 贪婪法。首先将n个区间按右端点b ...

qq_40688707的博客 1471

区间覆盖问题

参考文章(侵删): 贪心法求解三种有关区间覆盖问题贪心算法-最大不相交区间数问题   一. 算法描述 1. 区间完全覆盖问题 问题描述:给定一个长度为m的区间,再给出n条线段的起点和终点(注意这里是闭区间),求最少使用多少条线段可以将整个区间完全覆盖。   样例: 区间长度8,可选的覆盖线段[2,6],[1,4],[3,6],[3,7],[6,8],[2,4],[3,5] 解题过程...

SJLin 2569

区间贪心

问题1: 数轴上有n个开区间(ai, bi)。选择尽量多个区间,使得这些区间两两没有公共点。 策略: 如果x区间完全包含了y区间,那么我们选择y区间 按照右端点bi从小到大排序,从第一个区间开始选 如果目前的区间与上一个区间有相交的部分,则排除掉(排除掉即该区间不再存在,而不z是不选择这样简单舍弃) 简单来说就是:一定选择第一个区间,每次选区间的时候选择和上一个被选上的区间不相交的区间 思路: 首先对于x完全包含了y的情况,如下图所示,小区间为y,大区间为x 那么我们选择y区间,因..

amdkk的博客 436

【算法笔记】区间贪心

贪心 对于贪心问题,不要太关注过程或者方法,而应该关注结果的数据。 一般来讲,贪心问题至少要讨论两种情况。 大多数时候, 贪心 = 预处理 + 贪心算法, 例如排序, 或某种数学处理. 往往真正的贪心算法其实不难, 一般都是取某个值的最大最小 排序: 大于大的在前, 小于小的在前 贪心问题, 要优先考虑思维, 其次再从思维入手考虑具体的算法 区间贪心 一、线段覆盖 n个开区间(ai,bi),选择尽...

Suprit's blog 848

【贪心策略】区间问题、背包问题、贪心策略注意事项

贪心策略能解决的问题,往往可以分解为若干个子问题,并且每个子问题的最优解都可以使得总的解最优。相比DFS,贪心策略不需要穷举更多的可能,而是拥有了推知未来的能力,照某一个方案选择每一个子问题一定可以得到答案。贪心也可以理解为“最优子结构。

z135733的博客 1942

算法 1 - 5 贪心

有n个物体,第i个的重量为w(i),价值为v(i)。:有n个人,第i个人重量为w(i)。:先考虑当前最轻的人i,应该和能够与他一起坐船中的人中最重的人一起坐船,否则i一人坐一船。:数轴上有n个闭区间[ai,bi],选择尽量少的区间覆盖一条指定线段[s,t],ai<s。:给出n个物体,第i个物体重量为w(i)。:将bi从小到大排序,选择排序后的第一个区间,知道选完或不能选为止。:将ai从小到大排序,选择排序后的覆盖[s,t]最长的区间。:将bi从小到大排序,取第一个区间的最后一个点。

(^_^) 519
上一篇: 逆序对的两种解法(归并排序和树状数组)及其变种问题的一点思考
下一篇: 煎饼排序 (Stacks of Flapjacks, Uva 120)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值