方法:
1. 将所有区间按左端点从小到大排序
2. 从前往后依次枚举每个区间,在所有可能覆盖start的区间中,选择右端点最大的区间,然后将start更新成右端点的最大值
选往右覆盖最长的区间,不一定长度最长,而是右端点最靠右,长到左边去没有意义,“优势得优势到刀刃上,才能算优势”
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int n;
struct Range {
int l, r;
bool operator < (const Range &W) const {
return l < W.l;
}
} range[N];
int main () {
int st, ed;
scanf("%d%d", &st, &ed);
scanf("%d", &n);
for (int i = 0; i < n; i ++) {
int l, r;
scanf("%d%d", &l, &r);
range[i] = {l, r};
}
sort(range, range + n);
int res = 0;
bool success = false; //success作为flag 用来判断是否找到正确的方案
for (int i = 0; i < n; i ++) {
int j = i, r = -2e9; //r代表当前右端点的最大值,先赋为-∞
while (j < n && range[j].l <= st) { //遍历所有左端点在start左边(range[i].l <= st)的所有区间里面右端点的最大值r = max(r,range[j].r)是多少
r = max(r, range[j].r);
j ++;
}
if (r < st) { //无法覆盖左端点;或者说明覆盖过程中有空隙了
res = -1;
break;
}
res ++; // 先选上该区间,再看否已经覆盖完线段右端点了
if (r >=ed) {
success = true;
break;
}
st = r; //st更新成右端点最大值
i = j - 1; //因为下一步i++
}
if (!success) res = -1;
printf("%d\n", res);
return 0;
}
核心代码:
int res = 0;
bool success = false; //success作为flag 用来判断是否找到正确的方案
for (int i = 0; i < n; i ++) {
int j = i, r = -2e9; //r代表当前右端点的最大值,先赋为-∞
while (j < n && range[j].l <= st) { //遍历所有左端点在start左边(range[i].l <= st)的所有区间里面右端点的最大值r = max(r,range[j].r)是多少
r = max(r, range[j].r);
j ++;
}
if (r < st) { //无法覆盖左端点;或者说明覆盖过程中有空隙了
res = -1;
break;
}
res ++; // 先选上该区间,再看否已经覆盖完线段右端点了
if (r >=ed) {
success = true;
break;
}
st = r; //st更新成右端点最大值
i = j - 1; //因为下一步i++
}
双指针算法的应用:
遍历所有左端点在start左边(range[i].l <= st)的所有区间里面右端点的最大值r = max(r,range[j].r)是多少
for (int i = 0; i < n; i ++) {
int j = i, r = -2e9; //r代表当前右端点的最大值,先赋为-∞
while (j < n && range[j].l <= st) { //遍历所有左端点在start左边(range[i].l <= st)的所有区间里面右端点的最大值r = max(r,range[j].r)是多少
r = max(r, range[j].r);
j ++;
}