C-区间覆盖

题目:

数轴上有 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,否则不能处理区间左右端点含负数的情况。
    List item
  • 因为最后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;
}

样例运行:

在这里插入图片描述

发布了15 篇原创文章 · 获赞 0 · 访问量 802

猜你喜欢

转载自blog.csdn.net/qq_43746837/article/details/104734350
C-