区间选点
1. 将每个区间按照右端点从小到大进行排序
2. 从前往后枚举区间,end值初始化为无穷小
如果本次区间不能覆盖掉上次区间的右端点, ed < range[i].l
说明需要选择一个新的点, res ++ ; ed = range[i].r;
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
struct Range
{
int l, r;
} a[N];
bool cmp(Range x, Range y)
{
return x.r < y.r;
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) scanf("%d%d", &a[i].l, &a[i].r);
sort(a, a + n, cmp);
int res = 1, ed = a[0].r;
for (int i = 1; i < n; i++) {
if (a[i].l > ed) {
ed = a[i].r;
res ++;
}
}
printf("%d\n", res);
return 0;
}
最大不相交区间数量
方法一:
跟上题的代码一模一样,最大不相交区间数 == 最少覆盖区间点数
因为如果几个区间能被同一个点覆盖,说明他们相交了,所以有几个点就是有几个不相交区间
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
struct Range
{
int l, r;
} a[N];
bool cmp(Range x, Range y)
{
return x.r < y.r;
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) scanf("%d%d", &a[i].l, &a[i].r);
sort(a, a + n, cmp);
int res = 1, ed = a[0].r;
for (int i = 1; i < n; i++) {
if (a[i].l > ed) {
res ++;
ed = a[i].r;
}
}
printf("%d\n", res);
return 0;
}
方法二:
按左端点最小到大排序。可以设想,如果区间 i 的左端点小于等于 minR 时,更新 minR = min(minR, 区间 i 的右端点),因为,此区间跟之前遍历的区间为一组(因为它们都相交)。而要求最大不相交区间数,就要使得不相交的区间尽可能的多。如果当前区间大于 minR,则新增一组(抽象),更新 minR 为此区间的右端点。
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int, int> PII;
const int N = 100005;
int n;
PII s[N];
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d%d", &s[i].first, &s[i].second);
sort(s + 1, s + 1 + n);
int ans = 1, minR = s[1].second;
for(int i = 2; i <= n; i++){
if(s[i].first <= minR) minR = min(minR, s[i].second);
else ans++, minR = s[i].second;
}
printf("%d\n", ans);
return 0;
}
区间分组
从前往后枚举每个区间,判断此区间能否将其放到现有的组中
1. 如果一个区间的左端点比最小组的右端点要小,ranges[i].l <= heap.top() , 就开一个新组 heap.push(range[i].r);
2. 如果一个区间的左端点比最小组的右端点要大,则放在该组, heap.pop(), heap.push(range[i].r); 每组去除右端点最小的区间,只保留一个右端点较大的区间,这样heap有多少区间,就有多少组。
区间分组,在组内区间不相交的前提下,分成尽可能少的组。而不是尽可能多的组,因为一个区间一组,就是尽可能多组的答案。等效于把尽可能多的区间塞进同一组,要满足range[i].l > heap.top。heap 存储的是每个组的最右的端点,由于是小根堆 heap.top() 是对应的最小的最右点。
那如果遇到,塞不进去的情况呢?
就是 heap.top >= range[i].l,当前区间的左端点比最小的右端点还要小,放到任何一组都会有相交部分。那就需要新开一组,heap.push(range[i].r)。
1. 把所有区间按照左端点从小到大排序
2. 从前往后枚举每个区间,判断此区间能否将其放到现有的组中
3. heap有多少区间,就有多少组
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1e5 + 10;
struct Range
{
int l, r;
} a[N];
bool cmp(Range x, Range y)
{
return x.l < y.l;
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d%d", &a[i].l, &a[i].r);
sort(a + 1, a + n + 1, cmp);
priority_queue<int, vector<int>, greater<int> > heap;
for (int i = 1; i <= n; i++) {
if (heap.empty() || heap.top() >= a[i].l) heap.push(a[i].r);
else {
heap.pop(), heap.push(a[i].r);
}
}
printf("%d\n", heap.size());
return 0;
}
区间覆盖
1. 将所有区间按照左端点从小到大进行排序
2. 从前往后枚举每个区间,在所有能覆盖 start 的区间中,选择右端点的最大区间,然后将 start 更新成右端点的最大值。(双指针)
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
struct Range
{
int l, r;
} a[N];
bool cmp(Range x, Range y)
{
return x.l < y.l;
}
int main()
{
int s, t;
scanf("%d%d", &s, &t);
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) scanf("%d%d", &a[i].l, &a[i].r);
sort(a, a + n, cmp);
int res = 0;
bool flag = false;
for (int i = 0; i < n; i++) {
int j = i, r = -2e9;
while (j < n && a[j].l <= s) {
r = max(r, a[j].r);
j ++;
}
if (r < s) {
flag = false; break;
}
res ++;
if (r >= t) {
flag = true; break;
}
s = r;
i = j - 1;
}
if (flag) printf("%d\n", res);
else printf("-1\n");
return 0;
}