给定 N 个闭区间 [ai,bi],请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。
输出选择的点的最小数量。位于区间端点上的点也算作区间内。
输入格式
第一行包含整数 N,表示区间数。
接下来 N行,每行包含两个整数 ai,bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示所需的点的最小数量。
数据范围
1≤N≤105,
−109≤ai≤bi≤109
输入样例:
3
-1 1
2 4
3 5
输出样例:
2
可以使用贪心解决。
将区间按右端点排序
遍历区间,如果该区间中不包含最后选的那个点,则选取区间右端点。如果包含最后选的那个点,则跳过。
输出所选点的个数。
证明
假设最优解为 ans 个点,贪心算法求出的为 cnt 个点。 只需要证明 ans == cnt 即可。
因为 ans 是最优解,所以 ans <= cnt。
贪心算法求出的结果为 cnt,每次让选取点数+1的区间一定不相交。共计cnt个这样的区间。,为了覆盖这cnt个区间, 至少需要cnt个点。所以ans >= cnt。
综上: cnt == ans
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 100010;
//保存区间
vector<vector<int>> a(N,vector<int>(2,0));
int n;
int main()
{
cin >> n;
//读入区间
for(int i = 0; i< n; i++)
{
int l, r;
cin >> l >> r;
a[i][0] = l;
a[i][1] = r;
}
// 按右端点排序
sort(a.begin(), a.begin() + n, [](vector<int> &a, vector<int> &b){return a[1] < b[1];});
// res 保存答案,end 是当前选的点
int res = 0, end = -1e9 - 10;
// 遍历区间
for(int i = 0; i < n; i++)
{
// 如果当前选的点覆盖了该区间,则跳过
if(end >= a[i][0] && end <= a[i][1])
continue;
else
{
// 选的点+1, 选的点更新为区间右端点
res++;
end = a[i][1];
}
}
cout << res;
return 0;
}
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1e5+10;
struct Range
{
int l,r;
bool operator< (const Range &W)const
{
return r<W.r;
}
}ranges[N];
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
{
int l,r;
scanf("%d%d",&l,&r);
ranges[i]={l,r};
}
sort(ranges,ranges+n);
int res=0,st=-2e9;
for(int i=0;i<n;i++)
{
if(st<ranges[i].l)
{
res++;
st=ranges[i].r;
}
}
cout<< res <<endl;
return 0;
}
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e5 + 10;
struct Range
{
int l, r;
} ranges[N];
bool compareRanges(const Range &a, const Range &b)
{
return a.r < b.r;
}
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
int l, r;
scanf("%d%d", &l, &r);
ranges[i].l = l; ranges[i].r = r;
}
sort(ranges, ranges + n, compareRanges);
int res = 0, st = -2e9;
for (int i = 0; i < n; i++)
{
if (st < ranges[i].l)
{
res++;
st = ranges[i].r;
}
}
cout << res << endl;
return 0;
}