题目描述
数轴上有 n 个闭区间 [a_i, b_i]。取尽量少的点,使得每个区间内都至少有一个点(不同区间内含的点可以是同一个)
Input
第一行1个整数N(N<=100)
第2~N+1行,每行两个整数a,b(a,b<=100)
Output
一个整数,代表选点的数目
Examples
Input
2
1 5
4 6
Output
1
Input
3
1 3
2 5
4 6
Output
2
解题思路
首先从正常的思路来看,由于要选择最少的点,并且两个区间可以包含的是同一个点,那么如果有两个区间,则应该尽量选择第一个区间靠右的店,第二个区间中靠左的点,并且如果这两个区间有交集的话则可以只选择一个点,达到目的。
因此从贪心的角度来讲,这个题可以利用多关键字排序的方法,将所有区间按照右端点从小到大排序,右端点相等的区间可以按照左端点从小到大排序。然后先选取第一个区间的右端点,接下来比较该右端点是否在下一个区间内,若在则直接跳到下一个区间,若不在则需要从下一个区间中选取右端点作为下一个点,重复上述操作,直到遍历结束所有区间。
在这里使用dfs的方法实现以上思路。
代码
#include<iostream>
#include<algorithm>
using namespace std;
struct region
{
int a;//区间左端点
int b;//区间右端点
};
int n;
int number=0;
region m[100];
bool cmp(struct region x,struct region y)
{
if(x.b!=y.b)
return x.b<y.b;
else
return x.a<y.a;//这里<,>都是可以通过的
}
void select(int i,int score,region *num)//i记录数组第几个,num记录选了的个数
{
if(i>=n) return;
if(i==0)//第一个数组选取
{
number++;
select(i+1,m[i].b,m);
}
else
{
if(score>=m[i].a&&score<=m[i].b)//当上个点已经在下一个区间时不必再选取
select(i+1,score,m);
else//当上个点比下个区间的左端点小时需要再选取点(不可能比右端点大)
{
number++;
select(i+1,m[i].b,m);
}
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
cin>>m[i].a>>m[i].b;
sort(m,m+n,cmp);
select(0,0,m);
cout<<number<<endl;
return 0;
}
反思
贪心算法的具体证明很难,但大多都可以根据直觉有一个大致的判断,然后可以利用测试数据进行对应的修改完善,得到正确的贪心策略。因此,做题时一定不要直接跳到题目里面,而应该先从大局考虑问题的解决方法。