题目描述
给定N个闭区间[ai,bi]以及一个线段区间[s,t],请你选择尽量少的区间,将指定线段区间完全覆盖。
输出最少区间数,如果无法完全覆盖则输出-1。
输入格式
第一行包含两个整数s和t,表示给定线段区间的两个端点。
第二行包含整数N,表示给定区间数。
接下来N行,每行包含两个整数ai,bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示所需最少区间数。
如果无解,则输出-1。
数据范围
1≤N≤105,
−109≤ai≤bi≤109,
−109≤s≤t≤109
输入样例:
1 5
3
-1 3
2 4
3 5
输出样例:
2
主要考点
主要步骤
1. 将所有区间按照左端点从小到大排序
2. 从前往后依次枚举各个区间,在所能覆盖指定区间的区间中,找到右端点最靠右的区间, 然后将st更新为右端点的值.
C++代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int n;
struct Range{
int l, r;
bool operator < (const Range & R) const{
return l < R.l;
}
}range[N];
int main(){
int st, ed;
cin >> st >> ed >> n;
for(int i = 0; i < n; i ++) cin >> range[i].l >> range[i].r;
sort(range, range + n);//将各个区间按左端点从小到大排序
int res = 0;
bool flag = 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){//所有区间的有端点均小于指定区间左端点,即无解
res = -1;
break;
}
res ++;
if(r >= ed){//已经找到答案
flag = true;
break;
}
i = j - 1;
st = r;
}
if(flag) cout << res << endl;
else cout << "-1" << endl;
return 0;
}
为什么i = j-1
比如第一次时,while遍历所有的左端点比st小的区间,此时答案应该为j-1,比如答案为j=4时,但j=4这个区间我没用,所以我要i=j-1
同学,您好,感觉是不是不用加flag标识呢,因为如果没找到的话,res=-1,然后break了,直接输出res不就是吗
还有那个双指针没太搞明白,用到双指针的地方哪个是左指针,哪个是右指针呢,
这个是都可以的
其实这个地方是动态更新的左区间
不算是双指针
同学,不好意思哈,还是打扰您一下,请教一下,就是最外层的那个循环,i从0到n开始枚举区间,为啥中间可以直接i=j-1呢,为啥i可以直接跳到j-1这里,我好像这里不太明白
哦哦,同学,我好像想明白了,是因为前面的0到j,这些区间的右端点都比选到的右端点小,所以可以直接抛弃,
对的,那些点已经被抛弃了,但是用j模拟,i没变,所以把j赋值给i,让i改变,hh