每周一算法:区间覆盖

问题描述

给定 N N N个闭区间 [ a i , b i ] [a_i,b_i] [ai,bi],以及一个线段区间 [ s , t ] [s,t] [s,t],请你选择尽量少的区间,将指定线段区间完全覆盖。

输出最少区间数,如果无法完全覆盖则输出 − 1 -1 −1。

输入格式

第一行包含两个整数 s s s和 t t t,表示给定线段区间的两个端点。

第二行包含整数 N N N,表示给定区间数。

接下来 N N N行,每行包含两个整数 a i , b i a_i,b_i ai,bi,表示一个区间的两个端点。

输出格式

输出一个整数,表示所需最少区间数。

如果无解,则输出 − 1 -1 −1。

数据范围

1 ≤ N ≤ 1 0 5 1≤N≤10^5 1≤N≤105, − 1 0 9 ≤ a i ≤ b i ≤ 1 0 9 -10^9≤a_i≤b_i≤10^9 −109≤ai≤bi≤109,

− 1 0 9 ≤ s ≤ t ≤ 1 0 9 -10^9≤s≤t≤10^9 −109≤s≤t≤109

输入样例

1 5
3
-1 3
2 4
3 5

输出样例

2

算法思想

从测试样例分析,要覆盖线段区间 [ 1 , 5 ] [1,5] [1,5],只需要 2 2 2个闭区间 [ − 1 , 3 ] [-1,3] [−1,3]和 [ 3 , 5 ] [3,5] [3,5],如下图所示。

可以采用贪心的思想来解决这个问题:

  • 首先将 N N N个闭区间 [ a i , b i ] [a_i,b_i] [ai,bi]按左端点排序
  • 从前向后遍历每个区间
    • 在所有能覆盖线段区间 [ s , t ] [s,t] [s,t]左端点 s s s的区间中,选择右端点最大的区间 [ a j , b j ] [a_j,b_j] [aj,bj],其中 a j ≤ s a_j\le s aj≤s,表示能够覆盖点 s s s。
    • 然后将 s s s更新成所有满足条件的区间中右端点的最大值
    • 重复上述过程,直到 s ≥ t s\ge t s≥t,表示线段区间被完全覆盖

时间复杂度

  • 将 n n n个区间排序的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)
  • 从前向后遍历每个区间,由于每个区间仅会处理 1 1 1次,因此时间复杂度为 O ( n ) O(n) O(n)

总的时间复杂度为 O ( n + n l o g n ) O(n + nlogn) O(n+nlogn)

代码实现

cpp 复制代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
typedef pair<int, int> PII;
PII st[N];
int main()
{
    int s, t, n, ans = 0, flag = 0;
    cin >> s >> t >> n;
    for(int i = 0; i < n; i ++) cin >> st[i].first >> st[i].second;
    //排序
    sort(st, st + n);
    for(int i = 0; i < n; i ++)
    {
    	//在所有能覆盖线段左端点s的区间中,选择右端点最大的区间
        int j = i, R = -1e9;
        while(j < n && st[j].first <= s) R = max(R, st[j ++].second);
        
        //无法覆盖左端点s
        if(R < s) break;
        
        ans ++; //需要的区间个数增加1
        
        s = R; //更新要覆盖的左端点
        if(s >= t) //覆盖完成
        {
            flag = 1;
            break;
        }
        
        i = j - 1; //继续从当前区间向后遍历
    }
    if(flag) cout << ans;
    else cout << -1;
    return 0;
}
相关推荐
唐诺2 小时前
几种广泛使用的 C++ 编译器
c++·编译器
XH华2 小时前
初识C语言之二维数组(下)
c语言·算法
南宫生2 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
不想当程序猿_2 小时前
【蓝桥杯每日一题】求和——前缀和
算法·前缀和·蓝桥杯
落魄君子3 小时前
GA-BP分类-遗传算法(Genetic Algorithm)和反向传播算法(Backpropagation)
算法·分类·数据挖掘
冷眼看人间恩怨3 小时前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
菜鸡中的奋斗鸡→挣扎鸡3 小时前
滑动窗口 + 算法复习
数据结构·算法
红龙创客3 小时前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++
Lenyiin3 小时前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin
郭wes代码3 小时前
Cmd命令大全(万字详细版)
python·算法·小程序