// 将所有存在交集的区间合并
void merge(vector<PII> &segs)
{
vector<PII> res;
sort(segs.begin(), segs.end());
int st = -2e9, ed = -2e9;
for (auto seg : segs)
if (ed < seg.first)
{
if (st != -2e9) res.push_back({st, ed});
st = seg.first, ed = seg.second;
}
else ed = max(ed, seg.second);
if (st != -2e9) res.push_back({st, ed});
segs = res;
}
803. 区间合并
给定 n 个区间 [li,ri],要求合并所有有交集的区间。
注意如果在端点处相交,也算有交集。输出合并完成后的区间个数。
例如:[1,3]
和 [2,6] 可以合并为一个区间 [1,6]。
输入格式
第一行包含整数 n。
接下来 n行,每行包含两个整数 l 和 r。
输出格式
共一行,包含一个整数,表示合并区间完成后的区间个数。
数据范围
1≤n≤100000
,
−109≤li≤ri≤109
输入样例:
5
1 2
2 4
5 6
7 8
7 9
输出样例:
3
#include <iostream> // 引入输入输出流库
#include <vector> // 引入向量容器库
#include <algorithm> // 引入算法库
using namespace std; // 使用标准命名空间
typedef pair<int, int> PII; // 定义一个别名PII,表示一对整数
void merge(vector<PII> &segs) // 定义一个函数merge,接受一个向量参数segs,类型为pair<int, int>的向量
{
vector<PII> res; // 定义一个空向量res,用于存储合并后的线段
sort(segs.begin(), segs.end()); // 对segs进行排序,按照线段的起点从小到大排序
int st = -2e9, ed = -2e9; // 初始化st和ed为-2e9,表示当前线段的起点和终点
for (auto seg : segs) // 遍历segs中的每个线段
if (ed < seg.first) // 如果当前线段的起点大于上一个线段的终点
{
if (st != -2e9) res.push_back({st, ed}); // 如果st不等于-2e9,说明有有效的线段被合并,将其添加到res中
st = seg.first, ed = seg.second; // 更新st和ed为当前线段的起点和终点
}
else ed = max(ed, seg.second); // 如果当前线段的起点小于等于上一个线段的终点,更新ed为当前线段的终点和上一个线段的终点中的较大值
if (st != -2e9) res.push_back({st, ed}); // 如果最后还有有效的线段没有被合并,将其添加到res中
segs = res; // 将合并后的线段赋值给segs
}
int main() // 主函数
{
int n; // 定义一个整型变量n,表示线段的数量
scanf("%d", &n); // 从标准输入读取n的值
vector<PII> segs; // 定义一个空向量segs,用于存储输入的线段
for (int i = 0; i < n; i ++ ) // 循环n次,读取n个线段的起点和终点
{
int l, r; // 定义两个整型变量l和r,表示线段的起点和终点
scanf("%d%d", &l, &r); // 从标准输入读取l和r的值
segs.push_back({l, r}); // 将起点和终点组成的pair添加到segs中
}
merge(segs); // 调用merge函数,合并segs中的线段
cout << segs.size() << endl; // 输出合并后的线段数量
return 0; // 返回0,表示程序正常结束
}
贪心按左端点
思路:
就是以左端点进行排序,每次让下一个集合与该集合的右端点进行比较即可。
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
struct Range
{
int l,r;
bool operator< (const Range&W)const
{
return l < W.l;
}
}range[N]; //重载小于号,使其以左端点进行排序
int main()
{
int n;
cin >> 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 = 1;
int maxr = range[0].r;
for(int i = 1;i < n;i ++)
{
if(range[i].l <= maxr) maxr = max(maxr,range[i].r);
else
{
res ++;
maxr = range[i].r;
}
}
cout << res << endl;
return 0;
}
作者:想想这道题怎么做
链接:https://www.acwing.com/solution/content/10915/
来源:AcWing
贪心以右端点排序
思路与上一种差不多,不过右端点需要从右到左来合并区间
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1e5 + 10;
struct Range
{
int l,r;
bool operator< (const Range&W)const
{
return r < W.r;
}
}range[N];
int main()
{
int n;
cin >> 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 = 1;
int maxl = range[n - 1].l;
for(int i = n - 2;i >= 0;i --)
{
if(range[i].r >= maxl) maxl = min(maxl,range[i].l);
else
{
res ++;
maxl = range[i].l;
}
}
cout << res << endl;
return 0;
}
作者:想想这道题怎么做
链接:https://www.acwing.com/solution/content/10915/
来源:AcWing
简单方法
:
#include<bits/stdc++.h>
using namespace std;
const int N= 100010;
typedef pair<int ,int> PII;
PII a[N];
signed main()
{
int n;
cin>>n;
for(int i = 1 ; i<= n ; i++)
{
cin>>a[i].first>>a[i].second;
}
sort(a+1,a+1+n);
int ed = a[1].second,ans = 0;
for(int i = 2 ; i <= n ; i++)
{
if(ed >= a[i].first)
{
ed = max(ed,a[i].second);
}
else ans++,ed = a[i].second;
}
cout<<ans+1<<endl;
}