【Week3作业 C】区间覆盖【贪心】

题意:

数轴上有n(1<=n<=25000)个闭区间[ai,bi],选择尽量少的区间覆盖一条指定线段[1,T] (1<=T<=1000000)。覆盖整点,即[1,2]+[3,4]可以覆盖[1,4]。不可能办到输出-1。输入第一行为n和T,之后N行每行一个闭区间。输出选择区间的数目,不可能办到输出-1。


思路:

贪心准则:从已覆盖的区间段中选出一个a,它有最大的b,然后删除最大b之前的区间。
首先读入时如果区间在[1,T]之外,直接不记录。读完所有区间后应判断是否没有在[1,T]之间的区间。
之后对所有区间按a从小到大,b从大到小排序。
按照贪心准则,一开始没选区间时,从a<=1的区间中找到最大b。如果没有a<=1且b>1的区间,输出-1。
此时已经新覆盖了[lasta,lastb],需要从[lasta,lastb+1]中寻找一个a,它有最大b。找到后应更改lasta与lastb。
注意到最后一个区间时,应判断是否选了新区间。
在这里插入图片描述


总结:

一道贪心题,贪心准则好想,但实现起来有些困难。如果简单的找到最大b后删除b之前的区间会TLE。所以直接遍历数组,当找到最大b时,数组索引之前的区间就是要删除的区间,不用删除。
同时应注意不能覆盖的各种情况,少判断一种都会WA。


代码:

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct qujian
{
	int a,b;
	qujian(int a1=0,int b1=0)
	{
		a=a1,b=b1;
	}
};
bool cmp(const qujian&q1,const qujian&q2)
{
	if(q1.a<q2.a)	return true;
	else if(q1.a>q2.a)	return false;
	else
	{
		if(q1.b>q2.b)	return true;
		else return false;
	}
}
int main()
{
	std::ios::sync_with_stdio(false);
	int N,T;
	cin>>N>>T;
	vector<qujian> v;
	v.reserve(25000);	//使vector容量扩充,避免多次扩充操作,也防止MLE 
	for(int i=0; i<N; i++)
	{
		int a,b;
		cin>>a>>b;
		if(b<1||a>T)	continue;	//砍掉[1,T]之外的区间 
		qujian q(a,b);
		v.push_back(q);
	}
	if(v.empty())	//没有在[1,T]的区间 
	{
		cout<<-1<<endl;
		return 0;
	}
	int ans=0;
	sort(v.begin(),v.end(),cmp);	//按a从小到大排序
	//从a<=1的区间找到最大b
	int index=0;	//vector下标
	int maxb=1; 
	for(;index<v.size();index++)
	{
		if(v[index].a<=1&&v[index].b>maxb)
			maxb=v[index].b;
		else if(v[index].a>1)	
			break;
	} 
	ans++;	//覆盖了[1,maxb] 
	if(maxb==1)	//没有a<=1&&b>1的区间 
	{
		cout<<-1<<endl;
		return 0;
	}
	int lasta=1,lastb=maxb;
	
	//此时已经新覆盖了[lasta,lastb],需要从[lasta,lastb+1]中寻找一个a,它有maxb
	for(;index<v.size();index++)
	{
		//此时已经覆盖了[lasta,lastb],判断是否已经覆盖[1,T]
		if(lastb>=T)	break;
		if(v[index].a>=lasta&&v[index].a<=lastb+1&&v[index].b>maxb)
			maxb=v[index].b;
		else if(v[index].a>lastb+1)	//选取了新区间,应更改lasta和lastb 
		{
			if(maxb>lastb)	//选了新区间
			{
				lasta=lastb+1,lastb=maxb;
				ans++;
				index--;
				continue;
			} 
			else break;
		}
		if(index==v.size()-1)	//最后一个,判断是否选了新区间
		{
			if(maxb>lastb)	//选了
			{
				lasta=lastb,lastb=maxb;
				ans++;
			}
			//没选,什么也不做(此时覆盖不了[1,T]) 
		} 
	}
	//判断是否覆盖了[1,T]
	if(lastb>=T)	cout<<ans<<endl;
	else cout<<-1<<endl; 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值