程序设计思维与实践 Week3 作业C 区间覆盖

题意:
题目给出数轴上的n个区间,并且给出一个已知的线段,要求从中选择最少的的区间来覆盖这个线段,并且要求的是覆盖整点即可。输出能覆盖该线段的最少的区间数,若不存在能覆盖该线段的区间,则输出-1。


思路:
首先用结体记录下区间,但若区间的右端点小于线段的左端点,或者区间的左端点大于线段的右端点,则不保存。剩下的保存后进行排序,即以左端点a从小到大进行排序,再以右端点的从小到达排序。然后先设置起点q为0(线段的起始点为1),因为只要进行整点覆盖即可,故区间之间可以隔一个点,故差为1。然后开始对保存的数组进行遍历。即在a<q+1的条件下(在该条件下即可覆盖到起点),寻找区间右端点b为最大的区间,找到后。区间数加一,并将起点q设置为该区间的右端点,下一次再开始在a<q+1的条件下寻找右端点最大的区间。依次进行下去。其中若在寻找的过程中,起点没有移动,则说明其中有点没有覆盖,即可退出。当最后遍历结束的时候,判断最后所到达的右端点与线段的右端点的大小关系。若没有大于等于线段的右端点则覆盖失败。


总结:
主要还是先对区间进行排序,然后依次从起点选择能到达的最远的那个区间。并且在其中在当前线段之外的可以不考虑。另外就是整点覆盖的问题。即【1,2】,【3,4】可以覆盖【1,4】。故在起点可以在上一个起点往后一个点的位置。


代码:

#include <stdio.h>
#include <algorithm>
using namespace std;

struct P {
	int a; //记录左右端点
	int b;
	bool operator<(const P& p) const{
		if (a != p.a) return a < p.a;
		if (b != p.b)  return b < p.b;
	}
};

int main() {
	int n;
	scanf("%d", &n);   //区间数 
	P* p = new P[n];

	int t;
	scanf("%d", &t);  //终点 

	int x, y;
	int count = 0;
	for (int i = 0; i < n; i++) {  //读取区间数
		scanf("%d %d", &x, &y);
		if (x > t || y < 1) continue; //不在所需要区间段
		p[count].a = x;
		p[count].b = y;
		count++;
	}
	sort(p, p+count);	
	if (count == 0) {  //区间段内不存在
		printf("%d\n", -1);
		return 0;
	}
				
	int num = 0;    //已经加入的区间数 
	int q = 0;   //总的区间的当前的起点 
	
	for (int j = 0; j < count; ) {
		if (p[j].a > q+1) {  //即前面有点没有被覆盖,不成立 
			num = -1;
			break;
		}
		int temp=q;   //记录下一个起点 
		while ( j<count && (p[j].a<= q+1)) {	
			if (p[j].b > temp) {  //记录下洗一个能到达的最远的区间
				temp = p[j].b;
			}
				j++;		
		}
		
		if(temp==q){  
			break;  //起点没有移动 
		}else{
			q=temp; //增加了一个区间,记录右端点
			num++;
		}			
		if (temp >= t || j==count) break;  //已经到达,或者区间遍历结束 
	}
	if (q<t) num = -1;
	printf("%d\n", num);
	delete[]p;
	return 0;
}

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值