区间覆盖问题
问题重述:
给你n个区间[a,b],选择尽量少的区间去覆盖一条指定的线段[s,t].
算法分析:
我们可以先对a进行排序,从小到大。然后,在选择一个起点在前一个区间终点内的最大区间(如果,找不到则说明没法覆盖指定的线段)。就这样一直遍历下去直到找到可以覆盖整条线段的解为止。
上面讲的是什么意思呢?直白一点,举个例子:
------->我们假设前一个区间[s1,e1]。则,我们可以遍历,起点小于s1的所有区间,然后找到一个终点最大的一个区间即可。如果,在[s1,e1]内找不到起点比s1小的区间。则,说明找不到区间可以覆盖指定的线段[s,t].此时,直接跳出无需再遍历了。
实战演习:Click Here~
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <cmath> using namespace std; const int N = 1E4 + 5; struct Point { double a,b; bool operator < (const Point x)const { if(x.a != a) return a < x.a; return b > x.b; } }; int main() { Point p[N]; int T,n; scanf("%d",&T); while(T--) { int k = 0; double w,h,x,r,t; scanf("%d%lf%lf",&n,&w,&h); for(int i = 0;i < n;++i){ scanf("%lf%lf",&x,&r); if(2.0*r <= h)continue; t = sqrt(r*r-h*h/4.0); p[k].a = (x-t)>0?(x-t):0; p[k].b = (x+t)>w?w:(x+t); k++; } sort(p,p+k); if(p[0].a > 0){ printf("0\n"); continue; } int cnt = 1; //最后的一个区间无法加入,所以提前增加 double b = 0,e = 0; //前一区间结束的位置 for(int i = 0;b < w&&i < k;++i) // !!!!b < w 防止多算一个 { if(p[i].a <= e){ b = max(p[i].b,b); //选择尽量大的区间 }else { e = b; //更换新的区间 cnt++; } if(p[i].a <= e){ //已经找到了最长的一个区间后 b = max(p[i].b,b); }else { break; } } printf("%d\n",b >= w?cnt : 0); } return 0; }