题意:
数轴上有n个区间[ai,bi],选择尽可能少的区间覆盖一条指定线段[1,t]。要求覆盖整点,即[1,2]和[3,4]可以覆盖[1,4]。
题目分析:
贪心策略:
预处理:将与[1,t]没有交集的区间去掉,剩下的区间按a升序排列。如果最小区间的左端点>1,无解。
start为待覆盖区间的左端点,end为当前覆盖区间的右端点,选取以<=start为起点的所有区间中右端点最大的区间[ai,bi],更新start=end+1,end=bi,直到全覆盖。
证明:左端点升序排列后,在向后遍历区间时,可以找到一个位置,该位置左边的区间左端点符合要求,该位置右边的区间左端点不符合要求。在遍历所有左端点符合要求的区间时,找到右端点最大的区间,可以覆盖尽量远的区间,因此,贪心策略是正确的。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
struct range{
int a,b;
bool operator<(const range &r)const{
if(a!=r.a) return a<r.a;
}
};
int cnt;
range ran[25005];
int main()
{
int n,t; scanf("%d%d",&n,&t);
int a,b; int temp=0;
for(int i=0;i<n;i++){
scanf("%d%d",&a,&b);
//预处理 将在1-t的区间加入
if(!(a>t || b<1)){
ran[temp].a=a; ran[temp].b=b;
temp++;
}
}
bool ok=1;
if(!temp) {ok=0; //cout<<"没有在1-t的区间\n"<<endl;
}
sort(ran,ran+temp);
if(ran[0].a>1){ok=0; //cout<<"最小的左端> 1"<<endl;
}
int start=1;int end=0;
int pos=0; int cnt=0;
while(end<t){//未完全覆盖
start=end+1;
for(int i=pos;i<temp;i++){
if(ran[i].a<=start)
{
if(ran[i].b>end) end=ran[i].b;
}
else{
pos=i;break;
}
}
if(start>end){
ok=0;
// cout<<"start="<<start<<" end="<<end<<endl;
break;
}
else cnt++;
}
if(ok==0) cout<<"-1"<<endl;
if(end>=t) cout<<cnt<<endl;
return 0;
}