题意:
题目给出数轴上的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;
}