贪心--区间覆盖问题

题目描述

数轴上有 n (1<=n<=25000)个闭区间 [ai, bi],选择尽量少的区间覆盖一条指定线段 [1, t]( 1<=t<=1,000,000)。
覆盖整点,即(1,2)+(3,4)可以覆盖(1,4)。
不可能办到输出-1

Input

第一行:N和T
第二行至N+1行: 每一行一个闭区间。

Output

选择的区间的数目,不可能办到输出-1

Example

Input

3 10
1 7
3 6
6 10

Output
2

Note

这道题输入数据很多,请用scanf而不是cin

解题思路

由于要选择尽量少的区间,则首先应该想到区间的长度应尽量长,并且需要满足区间尽量连续的覆盖线段,因此可使用关键字排序的方法,按照区间左端点的从小到的顺序,相等的再按照右端点从大到小的顺序进行排序。然后设置初始的右端点为1,判断该端点是否在第一个区间的范围内,如果在则用while循环找到包含这个点的最大区间,然后将右端点赋值为原来的点和区间右端点中的较大者,并且选择区间的记录+1。
需要注意的是,由于需要包含的区间从1开始,到t结束,因此在递归之前可以进行预处理,将左端点小于1的区间置为1,右端点大于t的区间置为t。

代码

#include<iostream>
#include<algorithm>
using namespace std;
struct region
{
	int a;//区间左端点 
	int b;//区间右端点 
};
int n,t;
int number=0;
region m[25000]; 
bool cmp(struct region x,struct region y)
{
	if(x.a!=y.a)
	    return x.a<y.a;
	else
	    return x.b>y.b;
}
int main()
{
	scanf("%d%d",&n,&t);
	for(int i=0;i<n;i++)
	{
		scanf("%d%d",&m[i].a,&m[i].b);
		if(m[i].a<1)  //对每个区间进行预处理
			m[i].a=1;
		if(m[i].b>t) 
			m[i].b=t;
	} 
	sort(&m[0],&m[0]+n,cmp);
	if(m[0].a!=1) 
	{
	    printf("-1\n");
		return 0;
	}
    int s=1;//每一次的右端点 
    int num=0;//记录选区的数组个数 
    int i=0;//遍历m数组的第几个 
    while(i<n&&s<=t)
	{
        int max=-1;
        if(m[i].a>s) 
	       break;
        while(i<n&&m[i].a<=s)// 找到对应的右端点 
		{ 
           max=max>m[i].b?max:m[i].b;
           i++; 
        }
        s=max+1;
        num++;
    }
    if(s>t)
        printf("%d\n",num); 
    else
        printf("-1\n");
	return 0;
 } 

反思

本题的难点在于覆盖整点的问题,比如如果有区间(1,2),(2,3)(3,4),则只需要选取(1,2)(3,4)即可。这个可通过一个while循环巧妙实现。

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

猜你喜欢

转载自blog.csdn.net/weixin_43679657/article/details/105002935