贪心(一)

                                                    区间覆盖问题


问题重述:

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



贪心(一)

上一篇:[LeeCode]Search for a Range, 解题报告


下一篇:市场调查公司有哪些