主要思路:
一道简单的贪心应用
从左至右覆盖,R_covered记录已覆盖的区域的右端点(初始值为0)
将区间按照左端点排序(可以不用考虑右端点的顺序)
在区间集合S中选出一个右端点最大的(贪心原则)
集合S是左端点在R_covered左侧(可相等)的区间集合
执行上述循环直至(二选一):
- R_covered大于等于要求覆盖区间的右端点
- S为空集
若从1跳出循环则输出所用区间数;从2跳出则输出-1
简单的证明
选出最少的区间进行覆盖,显而易见我们要尽可能地选取长的区间。这里的“长”是指“有效长”——即超出已覆盖区域的长度,因为我们并不需要重叠的覆盖。因此,我们对区间进行排序的依据便是区间的右端点。
C - 区间覆盖
数轴上有 n (1<=n<=25000)个闭区间 [ai, bi]
选择尽量少的区间覆盖一条指定线段 [1, t](1<=t<=1,000,000)
覆盖整点,即(1,2)+(3,4)可以覆盖(1,4)。
不可能办到输出-1
Input
第一行:N和T
第二行至N+1行: 每一行一个闭区间。
Output
选择的区间的数目,不可能办到输出-1
Sample Input
3 10
1 7
3 6
6 10
Sample Output
2
- A Possible Solution
#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
typedef struct tag_interval {
int l, r;
tag_interval(int L, int R) {
l = L;
r = R;
}
bool operator < (const tag_interval& x) const {
if (l == x.l)
return r > x.r;
else
return l < x.l;
}
}interval;
int main() {
int n,t,R_covered=0,cnt=0;
vector<interval> v;
scanf("%d %d",&n,&t);
for(int i=0;i<n;i++){
int l,r;
scanf("%d %d",&l,&r);
if(r>=1){
interval tmp(l,r);
v.push_back(tmp);
}
}
sort(v.begin(),v.end());
while(!v.empty()){
int max=R_covered,index;
bool flag=false;
for(int i=0;i<v.size();i++){
if(v[i].l<=R_covered+1&&v[i].r>max){
index=i;
max=v[i].r;
flag=true;
}
if(v[i].l>R_covered+1)
break;
}
if(flag){
R_covered=v[index].r;
cnt++;
v.erase(v.begin()+index);
if(R_covered>=t)
break;
}
else{
break;
}
}
if(R_covered>=t)
printf("%d\n",cnt);
else
printf("-1\n");
return 0;
}