给定 N个闭区间 [ai,bi],请你将这些区间分成若干组,使得每组内部的区间两两之间(包括端点)没有交集,
并使得组数尽可能小。
输出最小组数。
输入格式
第一行包含整数 N,表示区间数。
接下来 N 行,每行包含两个整数 ai,bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示最小组数。
数据范围
1≤N≤105,−109≤ai≤bi≤109
输入:
3
-1 1
2 4
3 5
输出:
2
本题的巧妙之处在于:
//1.堆内维护的区间的右端从小到大
//2.数据在一组内没有相交的部分,证明他们在数轴上的投影是唯一的
//3.堆之前点右端的从小到大,与之对应序列控制左端从小到大完美的契合2
本人拙见:至于选左端从小到大排序还是右端从小到大排序是由问题的本质决定的,
这里你选右端从小到大排序,左端的情况是未知的,右端从小到大排序却在处理相交
的问题是合适的,这里大家自己举个例子就十分好理解了
算法
堆 + 排序(贪心的思想)
复杂度
O(NlogN + N);
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 100010;
//让每组所在的区间中没有重合的部分
struct Range
{
int l,r;
//运算符重载
bool operator<(const Range& w) const
{
return l < w.l;
}
}re[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin >> n;
for(int i = 0;i < n;i++)
{
int a,b;
cin >> a >> b;
re[i] = {a,b};
}
sort(re,re+n);
priority_queue<int,vector<int>,greater<int>> heap;
for(int i = 0;i < n;i++)
{
//为空或当前的左端比右端小,证明他们有重合的部分
if(!heap.size() || heap.top() >= re[i].l)
{
heap.push(re[i].r);
}
//若此时左端小于堆顶的右端,则满足不相交
//(序列在往后的左端一定比现在大,堆在往下的右端也一定比现在大)
else
{
heap.pop();
heap.push(re[i].r);
}
}
cout << heap.size();
return 0;
}