区间选点(贪心)
题目:区间选点(贪心)
题意:
给定 N 个闭区间 [ai,bi],要在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。
输出选择的点的最小数量。
位于区间端点上的点也算作区间内。
输入格式
第一行包含整数 N,表示区间数。
接下来 N 行,每行包含两个整数 ai,bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示所需的点的最小数量。
数据范围
1≤N≤1e5,
−1e9≤ai≤bi≤1e9
输入样例:
3
-1 1
2 4
3 5
输出样例:
2
样例解释:选择点1,4可以覆盖三个区间,答案为2。
题目分析:贪心。
解题步骤:
- 将所有区间按右端点从小到大排序。
- 从头到尾枚举每一个区间。
(1) 若该区间已有点被覆盖,则跳过。
(2) 若该区间没有点被覆盖,则选择该区间的右端点,此时答案 + 1。
贪心策略证明:
- 设贪心得出的答案是cnt,本题的正确答案是ans。
- 由于本题的答案ans是所有方案的最小值,所以必有ans <= cnt。
- 设在正确答案中有某些点不是某个区间的右端点,由于区间是按右端点从小到大排序的,所以选择右端点能够为后面的区间获得更多的包含该点的可能,所以将正确答案中不是某个区间的右端点的点替换成右端点是更优的,所以有cnt <= ans。
- 由于ans <= cnt且cnt <= ans,得cnt = ans。
AC代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
struct st{
int x, y;
bool operator < (const st &X) const{
return y < X.y;
}
}a[N];
int n;
void solve(){
scanf("%d", &n);
for(int i = 1;i <= n;i++) scanf("%d %d", &a[i].x, &a[i].y);
sort(a + 1, a + 1 + n);
int res = 0, t = -2e9;
for(int i = 1;i <= n;i++){
if(a[i].x > t){
res++;
t = a[i].y;
}
}
printf("%d\n", res);
}
int main(){
solve();
return 0;
}
时间复杂度:O(nlogn)。
空间复杂度:O(n)。