区间覆盖

问题描述:

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

样例输入:

3 10
1 7
3 6
6 10

样例输出:

2

解题思路:

首先,这个问题是一个贪心问题,首先要确定贪心求解策略,为尽量选择少的区间去覆盖一条指定线段,那么可以从起点最小的区间开始,选择同一起点上最长的区间,然后去遍历所有区间,选择一条起点在该区间内并且最长的区间,并且下一次遍历时更新起点为该区间,依次类推,知道覆盖完毕为止,否则不可能覆盖。

对于以上操作,我们可以进一步简化,由于要覆盖的区间是已知的,那么我们可以在输入数据时对数据就行处理,只保留要覆盖区间内的部分,这样我们保存的所有区间都是在要覆盖区间内的。

再输入完毕后要对所有区间进行排序,若起点不相同,就按起点升序拍,否则按终点升序拍,拍好序后,所有的区间都按数轴的前后顺序保存在数组中,如果最考前的区间,也就是数组第一个元素的起点,不是要覆盖区间的起点,那么不可能覆盖,否则,选择在起点的一个最长区间,进行遍历,然后找与起点区间有交叉的区间的最长区间 (!!注意!!这里最长区间的起点也可以是起点终点加1)
,更新起点,一直到覆盖位置,否则,找不到这样的区间,不能覆盖。

代码:

#include<cstdio>
#include<algorithm>
using namespace std;
struct section { //区间结构体
	int start;
	int end;
	bool operator < (const section s)const {
		if(start!=s.start)	return start < s.start; //第一字典序升序
		return end < s.end; //第二字典序升序
	}
};
int n, t;
int main()
{
	section ss[25000];
	scanf("%d",&n);
	scanf("%d",&t);
	for (int i = 0; i < n; i++)
	{
		int b, e;
		scanf("%d", &b);
		scanf("%d", &e);	
		if(b < 1)  //输入时对每个区间处理
			b = 1;
		if(e > t) 
			e = t;
		ss[i].start=b;
		ss[i].end=e;
	}
	sort(ss,ss+n);
	if (ss[0].start > 1)
	{
		printf("-1"); //如果最靠前的区间起点不是1,不可能覆盖
	}
	else
	{
		int flag=0;
		int down=ss[0].end; 
		for(int i=1;i<n;i++)
		{
			if(ss[i].start>1)
				break;
			if((ss[i].start==1)&&(ss[i].end>down))
			{ //找到起点为1的最长区间
				flag=i;
				down=ss[i].end;
			}		
		}
		int up;
		int number=1;
		while(down!=t) 
		{
			int qq=0;
			up=down+1;	  //注意加一!!!
			for(int i=flag;i<n;i++)
			{
				if(ss[i].start>up)
				{
					flag=i;
					break;
				}	
				else if(ss[i].start<=up&&ss[i].end>=down)
				{  //找到符合要求的最长区间
					qq=i;
					down=ss[i].end;  
				}			
			}
			if(up>down)//没有找到
			{
				number=-1;
				break;
				
			}	
			else{
				flag=qq+1; //找到了,从此区间后遍历,此区间为起点
				number++;
			}
		}
		printf("%d\n",number);
	}
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值