题目
给定 N个闭区间 [ai,bi]以及一个线段区间 [s,t],请你选择尽量少的区间,将指定线段区间完全覆盖。
输出最少区间数,如果无法完全覆盖则输出 −1。
输入格式
第一行包含两个整数 s 和 t,表示给定线段区间的两个端点。
第二行包含整数 N,表示给定区间数。
接下来 N 行,每行包含两个整数 ai,bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示所需最少区间数。
如果无解,则输出 −1。
数据范围
1 <= N <= 1e5
分析思路
- 对区间结构按左端排序
- 从前往后一次枚举每个区间:判断左端点在st之前的区间,循环找到最大右端点,如果右端点也在st之前,说明无法覆盖。
- 如果找到左端点在st之前,右端点在st之后的区间,(i++)
- 每一次循环都使用j遍历之后的区间没满足一次j < n && R[j].l <= st 就扩大一次这个区间 因为题目要求是输出最小的区间数
- 把start更新成right,保证后面的区间适合之前的区间有交集,从而形成对整个序列的覆盖
- 每一次循环最后把r值赋给st,下一次循环r又会从负无穷开始
- 如果遍历了所有的数组,还是没有覆盖最后的end,说明不能成功,如果最后超过了ed证明已经遍历结束 succ置为true 可以输出res
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
struct Range
{
int l,r;
bool operator < (const Range &w)const
{
return l < w.l;
}
}range[N];
int main()
{
int st,ed;
cin >> st >> ed;
int n;
cin >> n;
for(int i = 0;i < n;++i)
{
int x,y;
cin >> x >> y;
range[i] = {x,y};
}
sort(range,range + n);
int res = 0;
bool succ = false;
for(int i = 0;i < n;i++)
{
int j = i,r = -2e9;
while(j < n && range[j].l <= st)
{
r = max(r,range[j].r);
j++;
}
if(r < st) break;
res ++;
//到底了succ为true表示res确定
if(r >= ed)
{
succ = true;
break;
}
//每一次循环最后把r值赋给st,下一次循环r又会从负无穷开始
st = r;
//因为循环完了i会++,这里-1是调整i指向的位置
i = j - 1;
}
if(!succ) res = -1;
cout << res << endl;
return 0;
}