贪心--区间选点问题

题目描述

数轴上有 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;
 } 

反思

贪心算法的具体证明很难,但大多都可以根据直觉有一个大致的判断,然后可以利用测试数据进行对应的修改完善,得到正确的贪心策略。因此,做题时一定不要直接跳到题目里面,而应该先从大局考虑问题的解决方法。

发布了16 篇原创文章 · 获赞 0 · 访问量 220

猜你喜欢

转载自blog.csdn.net/weixin_43679657/article/details/105002858
今日推荐