贪心(一)

来源:互联网 发布:新东方烹饪 知乎 编辑:程序博客网 时间:2024/06/03 04:24

                                                    区间覆盖问题


问题重述:

   给你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;}



1 0
原创粉丝点击