题目:
数轴上有 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行: 每一行一个闭区间。
Ouput:
选择的区间的数目,不可能办到输出-1。
Example:
Input:
3 10
1 7
3 6
6 10
Ouput:
2
Note:
这道题输入数据很多,请用scanf而不是cin。
题目分析:
(唉 ,天知道这道题我wa了多少次,wa到怀疑人生…)
首先这道题要选择尽量少的区间覆盖一条指定线段,根据贪心算法,先对区间进行一个sort排序,排序规则为先按a升序排序,再按b升序排序,排序之后的结果会是数组下标为0的点的左端点为最小的。
然后遍历这n个区间,每个node[i].a和定义的mina进行比较,
- 当node[i].a<=mina时,左端点不更新,只有右端点更大时更新maxb=node[i].b;
- 当node[i].a>mina时,并且当右端点更大的时候,考虑两种情况:
(1)node[i]的左端点比目前maxb+1(因为整点覆盖,所以当maxb=x的时候,可以覆盖到a+1)还大的时候,两区间间隔大于1,无法覆盖整段,无解。
(2)node[i]的左端点比目前maxb+1小的时候,代表有新的区间增加用来覆盖整个线段,区间数量ans++并更新mina=maxb+1。(一定要i- -!!!)
当达到覆盖条件,跳出循环,如果遍历结束,右端点maxb仍没有到达T,说明覆盖不完全,无解,否则输出计算出的区间数量。
再来说说我都是咋wa的吧
- 一开始定义的mina和maxb如图,这是不对的,因为题给要覆盖的线段时[1,t]所以mina应该赋值1,否则不能处理区间左右端点含负数的情况。
- 因为最后maxb>=T的时候跳出循环,所以一开始的ans初始化为0之后需要执行ans++。
- 之前我一直觉得根据这个排序下来,应该是node[0].a是最小的,node[N-1].b是最大的,所以在开始循环遍历之前进行了一个剪枝,即当最小的a都大于1或者最大的b都小于T的时候,无解。然鹅事实证明是我太天真,剪枝的前半部分是ok的,后半部分就不大行了,(举个极端的例子,当要覆盖[1,10]时 如果有两个区间,一个[1,10],一个[2,6]那么排序的结果node[N-1]为[2,6] 6<10,无解,但其实正确结果是有解且解为1的。去了后面那部分就能ac。
- 以及这道题的时间要求为1000 ms,很容易TE,复杂度需要控制在O(n)。
代码:
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
struct point
{
int a;
int b;
bool operator<(const point &p)const//先按左端点递增,再按右断点递增
{
if(a==p.a)
{
return b<p.b;
}
else
{
return a<p.a;
}
}
};
int main()
{
int N,T;
int ans=0;
scanf("%d%d",&N,&T);
point *node=new point[N];
for(int i=0;i<N;i++)
{
scanf("%d%d",&node[i].a,&node[i].b);
}
sort(node,node+N);
bool ok=false;
if(node[0].a>1)//||node[N-1].b<T)//不能做到覆盖 无解
{
printf("-1\n");
return 0;
}
else
{
ans=0;
//int mina=node[0].a;//mina maxb分别表示目前能覆盖区间的左右端点
//int maxb=node[0].b;
int mina,maxb;
mina=maxb=1;
ans++;
for(int i=0;i<N;i++)
{
if(node[i].a<=mina)//找出长度最长的
{
if(node[i].b>maxb)
{
maxb=node[i].b;//更新右端点
}
}
else if(mina<node[i].a)//新加区段
{
if(node[i].b>maxb)
{
if(maxb+1<node[i].a)//区间间隔超过1 ,无解
{
printf("-1\n");
return 0;
}
mina=maxb+1;ans++;i--;ok=true;
}
}
if(maxb>=T)//达到覆盖条件,跳出循环
{
break;
}
}
if(maxb<T)
{
printf("-1\n");
return 0;
}
else
{
printf("%d\n",ans);
}
//printf("%d\n",ans);
}
return 0;
}