区间贪心问题求解
区间贪心个人建议按照右端点从小到大排序
具体排序规则为:
如果右端点不同,选择右端点小的那个;如果右端点相同,则看左端点,选择(右端点-左端点)差值小的那个,也就是选择左端点大的那个。
bool cmp(HH a,HH b){//HH 为上一个文档里面定义的结构体,存放一个区间的左右断点
if(a.right!=b.right)
return a.right<b.right;
else
return a.left>b.left;
}
原理如下:
把一个个区间看作一个个会议,左端点为会议开始时间,右端点为会议结束时间,找出最多能参加几个会议?
优先选择最早结束的会议,也就是按照右端点从小到大排序。如果结束时间相同,则选择持续时间短的那个会议,这样可以腾出更多的时间参加其他的会议。
为什么不按照左端点从小到大排序呢?
因为最先开始的会议不一定最先结束,有可能最先开始的会议直接到最后一刻才结束,那就只能参加一个会议了。
参考题目:
P1803 凌乱的yyy / 线段覆盖 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
上述问题求解代码,按照右端点进行从小到大的排序:
#include<cstdio>
#include<cmath>
#include<iostream>
#include<string>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
struct HH{ //该结构体存放区间的左端点与右端点
int left,right;
};
bool cmp(HH a,HH b){ //按照右端点从小到大排序
if(a.right!=b.right)
return a.right<b.right;
else //如果右端点相同,则我们需要右端点-左端点差值小的那个,也就是左端点大的那个
return a.left>b.left;
}
int main(){
int n;//确定输入的区间组数
scanf("%d",&n);
vector<HH> a(n);//泛型为结构体HH的数组
for(int i=0;i<n;i++){
scanf("%d %d",&a[i].left,&a[i].right);//输入每组区间
}
sort(a.begin(),a.end(),cmp);//按照自定义cmp,对a数组进行排序
int sum=1;//数组中的第一个数,也就是结束时间最早的那个区间,一定会被选中,所以直接sum初始化为1
int tempRight=a[0].right;//同时需要有一个标记,标记最新选中的区间的右端点,到时候要判断下一个区间的左端点是否比他大
for(int i=0;i<n;i++){
if(a[i].left>=tempRight){//如果说下一个区间的左端点比最新选中区间的右端点大,那就没有重叠,可以参加下一个比赛
sum++;tempRight=a[i].right;//多一个可以参加的比赛(不重叠的区间),同时设置标志为这个区间的右端点
}
}
printf("%d",sum);
}