贪心
-
将区间按左端点排序;
-
若当前区间与前面所有的组有交集(堆顶元素大于区间左端点),直接入堆(另起一组)
-
若当前区间与堆顶元素所在组没有交集(堆顶元素小于等于区间左端点),将其加入堆顶元素所在组,并更新堆顶所在组的max_r (贪心:谁先用完就马上腾出来给下一个人)
-
贪心思路证明:
- 什么情况下组数最多:区间单独成组
- cnt为贪心解,ans为最优解
- cnt>=ans:
- 由于 当前区间与所有区间都有交集时,直接入堆,因此最后的结果是每个组内一定区间不相交,即合法的,合法解组数大于等于最优解组数,即 cnt>=ans,cnt<=n(区间数)
- cnt<=ans:
- 因为贪心的思路是 将区间加入小根堆堆顶所在组,即 谁先用完马上腾出来给下一个人
- 试想这样的情况,当前区间可以加入前面所有的组,即 前面所有组的结束时间都小于当前区间开始时间,此时将区间加入结束时间最早的那组,后续区间就可以加入其他组了(后续区间的开始时间一定小于当前区间的开始时间,所以后续区间一定也可以加入当前区间下的所有组),按照这种流程添加区间,贪心解cnt一定是最少的
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int N=1e5+10;
struct Range{
int l,r;
bool operator< (const Range &d) const{
return l<d.l;
}
} range[N];
int n;
priority_queue<int,vector<int>,greater<int>> h;
int main(){
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);
for(int i=0;i<n;i++){
auto seg=range[i];
//堆为空或 区间与已维护的区间组都有交集
if(h.empty() || h.top()>=seg.l) h.push(seg.r);
//当前区间可以加入已维护的区间组,将其加入 区间组中r最小的组(堆顶)
else{
h.pop();
h.push(seg.r);
}
}
printf("%d\n",h.size());
return 0;
}