最小区间覆盖问题

给你一段区间1~t,有n个区间,求能覆盖完1~t的区间的最小个数,如果不能覆盖完输出-1

例题:poj2376

我们先假设已经覆盖了区间a~b,那么我们选择下一个区间的时候,为了保证最贪心的取,肯定会取左端点>=b+1的区间,这样重叠浪费的就少

然后我们再按贪心的思想,肯定是右端点越长覆盖的越多

那么我们现在开始思考这个问题

先按左端点从小到大排序,如果左端点相同的话按右端点从左到右排序

然后我们先判断第一个区间

如果第一个区间的左端点大于1 的话说明不能覆盖完1~t,直接输出-1

否则的话,last表示已经覆盖的区间的下标,我们把最原始的区间的下标last设为1,记录区间个数的变量flag设为1

然后我们从i=2开始遍历,当第i个区间的左端点<=last的右端点+1,并且第i个区间的右端点大于last的右端点的话,我们就从i开始找右端点最长的区间

找到之后个数++,i变化一下

最后判断一下已覆盖的区间last的右端点是否大于等于t,如果是就输出个数,如果不是说明没有覆盖完全,输出-1

/*

 .----------------.  .----------------.  .----------------.  .----------------. 
| .--------------. || .--------------. || .--------------. || .--------------. |
| |  ________    | || |  _________   | || | ____    ____ | || |     ____     | |
| | |_   ___ `.  | || | |_   ___  |  | || ||_   \  /   _|| || |   .'    `.   | |
| |   | |   `. \ | || |   | |_  \_|  | || |  |   \/   |  | || |  /  .--.  \  | |
| |   | |    | | | || |   |  _|  _   | || |  | |\  /| |  | || |  | |    | |  | |
| |  _| |___.' / | || |  _| |___/ |  | || | _| |_\/_| |_ | || |  \  `--'  /  | |
| | |________.'  | || | |_________|  | || ||_____||_____|| || |   `.____.'   | |
| |              | || |              | || |              | || |              | |
| '--------------' || '--------------' || '--------------' || '--------------' |
 '----------------'  '----------------'  '----------------'  '----------------'

*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<stack>
#define int long long
#define lowbit(x) x&(-x)
#define PI 3.1415926535
#define endl "\n"
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int gcd(int a,int b){
	return b>0 ? gcd(b,a%b):a;
}
const int N=25000+10;

/*
int dx[8]={-2,-2,-1,1,2,2,-1,1};
int dy[8]={-1,1,2,2,1,-1,-2,-2};
int dx[4]={0,-1,0,1};
int dy[4]={-1,0,1,0};
int dx[8]={-1,1,0,0,-1,-1,1,1};
int dy[8]={0,0,-1,1,-1,1,-1,1};
*/

struct name{
	int l,r;
}q[N];
int n;
bool cmp(name a,name b){
	if(a.l !=b.l )return a.l <=b.l ;
	return a.r <=b.r ;
}
void sove(){
	int t;
	cin>>n>>t;
	for(int i=1;i<=n;i++){
		cin>>q[i].l >>q[i].r ;
	}
	sort(q+1,q+1+n,cmp);
	if(q[1].l >1){
		cout<<-1<<endl;
		return ;
	}
	int flag=1,last=1;
	for(int i=2;i<=n;i++){
		if(q[i].l <=q[last].r +1&&q[i].r >q[last].r ){
			int j=i;
			while(q[i].l <=q[last].r +1&&i<=n){
				if(q[i].r >q[j].r ){
					j=i;
				}
				i++;
			}
			i=j;
			last=j;
			flag++;
			if(q[last].r >=t)break;
		}
	}
	if(q[last].r <t){
		cout<<-1<<endl;
	}else cout<<flag<<endl;
}

signed main(){
	ios::sync_with_stdio(false);
	cin.tie() ,cout.tie() ;
	int t=1;
//	cin>>t;
	while(t--){
		sove();
	}
	return 0;
}

 还有一个例题:

给你n个区间,选最少的区间来完全覆盖s~t这一段区间,

如果能覆盖完输出最小区间数量,如果不能的话我们就输出-1

思路:先按左端点从大到小排序

然后遍历n个区间

每次找左端点大于s的区间的最大右端点r

如果能找到的话就把s更新为r,数量++

如果找不到的话就把答案设为-1break

当然我们要额外判断一下我们更新的区间右端点是不是大于t,如果大于的话就输出个数

否则输出-1

/*

 .----------------.  .----------------.  .----------------.  .----------------. 
| .--------------. || .--------------. || .--------------. || .--------------. |
| |  ________    | || |  _________   | || | ____    ____ | || |     ____     | |
| | |_   ___ `.  | || | |_   ___  |  | || ||_   \  /   _|| || |   .'    `.   | |
| |   | |   `. \ | || |   | |_  \_|  | || |  |   \/   |  | || |  /  .--.  \  | |
| |   | |    | | | || |   |  _|  _   | || |  | |\  /| |  | || |  | |    | |  | |
| |  _| |___.' / | || |  _| |___/ |  | || | _| |_\/_| |_ | || |  \  `--'  /  | |
| | |________.'  | || | |_________|  | || ||_____||_____|| || |   `.____.'   | |
| |              | || |              | || |              | || |              | |
| '--------------' || '--------------' || '--------------' || '--------------' |
 '----------------'  '----------------'  '----------------'  '----------------'

*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<stack>
#define int long long
#define lowbit(x) x&(-x)
#define PI 3.1415926535
#define endl "\n"
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int gcd(int a,int b){
	return b>0 ? gcd(b,a%b):a;
}
const int N=1e5+10;
/*
int dx[8]={-2,-2,-1,1,2,2,-1,1};
int dy[8]={-1,1,2,2,1,-1,-2,-2};
int dx[4]={0,-1,0,1};
int dy[4]={-1,0,1,0};
int dx[8]={-1,1,0,0,-1,-1,1,1};
int dy[8]={0,0,-1,1,-1,1,-1,1};
*/

struct name{
	int l,r;
}q[N];
int n;
bool cmp(name a,name b){
	return a.l <b.l ;
}
void sove(){
	int s,t;
	cin>>s>>t;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>q[i].l >>q[i].r ;
	}
	sort(q+1,q+1+n,cmp);
	bool f=false;
	int res=0;
	for(int i=1;i<=n;i++){
		int j=i,r=-2e9;
		while(j<=n&&q[j].l <=s){
			r=max(r,q[j].r );
			j++;
		}
		if(r<s){
			res=-1;
			break;
		}
		res++;
		if(r>=t){
			f=true;
			break;
		}
		s=r;
		i=j-1;
	}
	if(!f)res=-1;
	cout<<res<<endl;
}

signed main(){
	ios::sync_with_stdio(false);
	cin.tie() ,cout.tie() ;
	int t=1;
//	cin>>t;
	while(t--){
		sove();
	}
	return 0;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值