题目描述
数轴上有 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循环巧妙实现。