每周一算法:区间覆盖

文章介绍了一个算法,通过贪心策略解决线段区间覆盖问题,涉及区间排序和覆盖决策,时间复杂度为O(n+nlogn)。

问题描述

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

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

输入格式

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

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

接下来NNN行,每行包含两个整数ai,bia_i,b_iai,bi,表示一个区间的两个端点。

输出格式

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

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

数据范围

1≤N≤1051≤N≤10^51N105−109≤ai≤bi≤109-10^9≤a_i≤b_i≤10^9109aibi109

−109≤s≤t≤109-10^9≤s≤t≤10^9109st109

输入样例

1 5
3
-1 3
2 4
3 5

输出样例

2

算法思想

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

在这里插入图片描述
可以采用贪心的思想来解决这个问题:

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

时间复杂度

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

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

代码实现

#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;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

少儿编程乔老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值