贪心
选择当前最优情况,通过局部最优解找到全局最优解
区间问题常见思路:
排序:按左端点/右端点/双关键字排序
通常
最大:右
最小:左
区间排序
步骤:
1.将每个区间按照右端点从小到大排序
2.从前往后枚举每个区间
如果当前区间已经包含点,换下一个区间
如果当前区间不包含点,尽量选取区间后面的点
#include <iostream>
#include <algorithm>
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;
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);
int res=0,ed=-1e9;
for(int i=0;i<n;i++){
if(ed<range[i].l){
res++;
ed=range[i].r;
}
}
printf("%d",res);
return 0;
}
最大不相交区间数量
跟上一题选择的区间一样,所以代码也一样
区间分组
1.将区间按左端点从小到大排序
2.从前往后处理每个区间,判断区间能否放入当前组(看下该组区间是否和当前区间有交集——某一组最后一个区间的最右端点max_r是否大于当前区间的左端点)
如果有交集,则开一个新的组
如果没有交集,则放在该组
小根堆heap存储每个组最右的端点,heap的大小等于组的个数
思想:heap.top()每次给出组中右端点最右的点,如果左端点比最右点还大,一定也不能放入其他组中
#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 l<w.l;
}
}range[N];
int main(){
int n;
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);
priority_queue<int,vector<int>,greater<int>>heap;//小根堆
for(int i=0;i<n;i++){
auto r=range[i];
if(heap.empty()||heap.top()>=r.l)heap.push(r.r);
else{
heap.pop();
heap.push(r.r);
}
}
printf("%d",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;
bool operator <(const Range& w)const{
return l<w.l;
}
}range[N];
int main(){
int st,ed;
scanf("%d%d",&st,&ed);
int n;
scanf("%d",&n);
for(int i=0;i<n;i++){
int l,r;
scanf("%d%d",&l,&r);
range[i]={l,r};
}
int ans=0;
bool success=false;
sort(range,range+n);
for(int i=0;i<n;i++){
//双指针算法
int j=i,r=-2e9;
//遍历所有左端点在start左边,求其右端点最大值
while(j<n&&range[j].l<=st){
r=max(r,range[j].r);
j++;
}
//最大值都小于start,无解
if(r<st){
ans=-1;
break;
}//即使满足该条件,但如果r<ed,最终还是没有结果,所以要加上success判断
ans++;//选中该区间,加上
if(r>=ed){
success=true;
break;//大于区间有边界,结束
}
st=r;
i=j-1;//for循环自动i++,所以先令i-1
}
if(!success){
ans=-1;
}
printf("%d",ans);
return 0;
}