区间合并
主要思想:给定很多区间。若两个区间有交集,将二者合并成一个区间。
具体做法:
- 先按照区间的左端点进行排序
- 然后遍历每个区间,根据不同的情况进行合并,有一下几种情况:
- 第一种情况,区间不变;
- 第二种情况,end更新为区间i的右端点;
- 以上两种情况,可以归结为end更新为max(end,r);r为区间右端点
- 第三种情况,将当前维护的区间加入结果,并将维护的区间更新为区间i;
下面给出区间合并的板子:
//区间合并
void merge(vector<PII> &segs){
vector<PII> res;
sort(segs.begin(),segs.end());//对pair先按左端点进行排序,再按右端点排序
int st = -2e9,ed = -2e9; //负无穷
for(auto seg : segs){
if(ed < seg.first){//当前维护区间与下一区间无交集
if(st != -2e9) res.push_back(seg);
st = seg.first,ed = seg.second;//后移,更新维护区间
}
else ed = max(ed, seg.second);//有交集,取两个区间的右端点最大值
}
if(st != -2e9) res.push_back({st,ed});//判断,然后将剩下的区间加入
segs = res;
}
下面来看具体的题目:
给定 n个区间 [ l r , r i ] [l_r,r_i] [lr,ri],要求合并所有有交集的区间。注意如果在端点处相交,也算有交集。输出合并完成后的区间个数。
例如:[1,3]和 [2,6]可以合并为一个区间 [1,6]。
输入格式:
第一行包含整数 n n n,接下来 n n n 行,每行包含两个整数 l l l和 r r r。
输出格式:
共一行,包含一个整数,表示合并区间完成后的区间个数。
输入样例:
5
1 2
2 4
5 6
7 8
7 9
输出样例:
3
本题思路:
- 读入区间端点 ( l , r ) , (l,r), (l,r),将其存入segs数组内,再设置一个结果数组res数组。这两个数组类型的vector类型,不过是键值对形式的;
- 将segs排序,设置左右端点 ( s t , e d ) (st,ed) (st,ed)为第一个维护的区间,初始都为无穷大;
- 遍历segs种的元素(区间),比较当前区间(维护区间)的ed和另一个区间seg的 l l l之间的关系;若 e d < l ed < l ed<l,说明这两个区间没有交集,则直接将此seg区间(注意不能是初始区间)加入到res中,并将待维护的区间变为seg(即更新区间,后移);若 e d < l ed < l ed<l不成立,有交集,则更新 e d ed ed为最大值(这里因为区间排好序,所以不用将st更新为最小)
- 最后判断segs是否为空,若不为空,则将最后剩余一个维护的区间加入res中;
实现代码:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef pair<int,int> PII;
vector<PII> segs;
int n;
void merge(vector<PII> &segs){
vector<PII> res;
sort(segs.begin(),segs.end());//对pair先按左端点进行排序
int st = -2e9,ed = -2e9; //负无穷
for(auto seg : segs){
if(ed < seg.first){//当前维护区间与下一区间无交集
if(st != -2e9) res.push_back(seg);
st = seg.first,ed = seg.second;//后移,更新维护区间
}
else ed = max(ed, seg.second);//有交集,取两个区间的右端点最大值
}
if(st != -2e9) res.push_back({st,ed});//判断,然后将剩下的区间加入
segs = res;
}
int main(){
cin >> n;
while(n--){
int l,r;
cin >> l >> r;
segs.push_back({l,r});
}
merge(segs);
cout << segs.size() << endl;
return 0;
}
以上就是区间合并的一些内容,后续如果有相关的习题再进行补充更新~