区间选点_Acwing_905——贪心
一道贪心小水题
题目
给定
N
N
N个闭区间
[
a
i
,
b
i
]
[a_i,b_i]
[ai,bi] ,请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。
输出选择的点的最小数量。
位于区间端点上的点也算作区间内。
输入格式
第一行包含整数N,表示区间数。
接下来N行,每行包含两个整数
a
i
a_i
ai,
b
i
b_i
bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示所需的点的最小数量。
数据范围
1
≤
N
≤
105
1≤N≤105
1≤N≤105
−
109
≤
a
i
≤
b
i
≤
109
−109≤a_i≤b_i≤109
−109≤ai≤bi≤109
输入样例
3
-1 1
2 4
3 5
输出样例
2
解题思路
1.将每个区间按右端点从小到大排序
2.从前往后依次枚举每个区间
– 如果当前区间已经包含点 则直接 pass
– 否则 选择当前区间的右端点 cnt++
证明
设ans为所有合法方案中的最小值
cnt为当前的一组可行方案
可根据夹逼定理证明ans=cnt
首先易得ans<=cnt
只需证ans>=cnt
如图 对于所有没被pass的区间
下一个选择点的区间在当前区间的右侧且无交集
即这些区间为cnt个相互之间没有交集的区间
那么至少需要cnt个点才能覆盖这些cnt个区间
则证明得出ans>=cnt
则ans=cnt
c++代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010;
int n;
struct Range{
int l,r;
/*结构体内重载小于号做法
bool operator<(const Range &W) const
{
return r<W.r;
}*/
}range[N];
bool cmp(struct Range a,struct Range b)
{
return a.r<b.r;
}
int main()
{
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,cmp);//将右端点从小到大进行排序
int res=0,ed=-2e9;
//res为最优端点总数
//ed为当前右端点 初始化为负无穷
for(int i=0;i<n;i++)
if(range[i].l>ed)
{
res++;
ed=range[i].r;
}
//遍历区间 判断当前区间是否包含点 不包含则res++并更新ed
cout<<res;
return 0;
}