最小区间覆盖问题

给你一段区间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
    评论
贪心算法最小区间覆盖是指给定一个大区间和多个小区间,要求找到最少的小区间来完全覆盖区间问题。其中,每个小区间都有一个开始时间和结束时间。贪心算法的思路是按照开始时间递增排序,然后从第一个小区间开始,选择与当前区间结束时间不重叠且结束时间最早的下一个区间,直到覆盖了整个大区间为止。 具体的解法可以按照以下步骤进行: 1. 将所有小区间按照开始时间递增排序,如果开始时间相同,则按照结束时间递增排序。 2. 初始化一个变量count,用于记录覆盖区间所需要的小区间的数量。 3. 设定一个变量end,表示当前选择的小区间的结束时间。 4. 遍历排序后的小区间列表,对于每个小区间: - 如果小区间的开始时间大于end,则说明当前小区间与之前选择的小区间不重叠,可以选择该小区间覆盖区间。 将该小区间的结束时间赋值给end,同时将count加1。 - 如果小区间的开始时间小于等于end,说明当前小区间与之前选择的小区间重叠,需要进行下一次遍历。 5. 如果end大于大区间的结束时间,则表示已经找到了能够完全覆盖区间最小区间集合,返回count的值;否则,返回-1,表示无法找到满足条件的最小区间覆盖。 这个问题可以使用贪心算法来解决,通过排序和遍历的方式选择合适的小区间覆盖区间,以达到最小覆盖的目标。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [贪心算法.doc](https://download.csdn.net/download/hqztrue2/11338380)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [贪心算法 --- 最小区间覆盖问题(POJ2376)](https://blog.csdn.net/WSSB____/article/details/126682938)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [贪心算法——最小区间覆盖问题](https://blog.csdn.net/mashizuren/article/details/113345347)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值