题目描述
给定 N 个闭区间 [ai,bi] 以及一个线段区间 [s,t],请你选择尽量少的区间,将指定线段区间完全覆盖。
输出最少区间数,如果无法完全覆盖则输出 −1。
输入格式
第一行包含两个整数 s 和 t,表示给定线段区间的两个端点。
第二行包含整数 N,表示给定区间数。
接下来 N 行,每行包含两个整数 ai,bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示所需最少区间数。
如果无解,则输出 −1。
数据范围
1≤N≤105,
−10^9≤ai≤bi≤10^9,
−10^9≤s≤t≤10^9
输入样例
1 5
3
-1 3
2 4
3 5
输出样例
2
算法步骤:
1.将所有区间按照左端点从小到大排序
2.从前往后依次枚举各区间,在所能覆盖指定区间的区间中,找到右端点最靠右的那个,然后将st更新为右端点的值
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n;
struct Range
{
int l, r;
bool operator< (const Range &W)const
{
return l < W.l;
}
}range[N];
int main()
{
int st, ed;// 指定线段的两个端点左st右ed
scanf("%d%d", &st, &ed);
scanf("%d", &n);
for (int i = 0; i < n; i ++ )
{
int l, r;
scanf("%d%d", &range[i].l, &range[i].r);
}
sort(range, range + n);
int res = 0;
bool success = false;
for (int i = 0; i < n; i ++ )
{
int j = i, r = -2e9;
while (j < n && range[j].l <= st)// 在所有左端点在st之前的区间中找
{
r = max(r, range[j].r);// 找右端点最靠右的那一个
j ++ ; // 记录这是找到第几个区间了
}
if (r < st) // 如果这些区间连最右端点都在st左边
{
res = -1; // 就省省力气break掉,不可能拼成
break;
}
// 如果最右端点在st右边,说明有戏,继续往下拼
res ++ ; // 记下这个最右端点所在的区间,把它的右端点设为新的st
if (r >= ed) // 往下拼之前先等一等,若刚才那个右端点比指定线段的ed还右
{
success = true; // 那就已经直接拼成了,不用继续往下拼了
break;
}
st = r; // 刚才提到右端点设为新st
i = j - 1; // 刚才记录第几个区间的时候,找最右找到头,多算了一个,这里减回来
}
if (!success) res = -1; // 没拼成res记为-1,拼成res记为用了几个区间
printf("%d\n", res);
return 0;
}