NYOJ 12 喷水装置(二)

来源:互联网 发布:淘宝联盟21号不能提现 编辑:程序博客网 时间:2024/06/04 23:28

此题应转化为区间覆盖问题,数轴上有 n 个闭区间 [ai, bi],选尽量少的区间覆盖一条指定线段 [s, t]。

将区间按 b 从小到大排序,用 sum 记录当前在线段上覆盖到的位置,每次对整个闭区间扫描,

扫描结果:

1. 线段上有的区间覆盖不到,则无法完成覆盖,跳出扫描循环;

2. 选择能覆盖到 sum 位置且最长的闭区间,用它来覆盖,贪心,保证选的区间少,sum += q[i].b - sum。

代码如下:

 #include<iostream>#include<stdio.h>#include<math.h>#include<algorithm>using namespace std;const int MAXN = 10000 + 5;int x[MAXN], r[MAXN];struct qu{    double a, b;} q[MAXN];bool cmp(qu a, qu b)   //按 b 升序排列{    return a.b < b.b;}int main(){    int t, n, w, h;    cin >>t;    while(t--)    {        cin >>n >>w >>h;        int s = 0;        int tx, tr;        while(n--)        {            cin >>tx >>tr;            if(2 * tr > h)  //只保存装置直径比草坪宽度大的            {                x[s ++] = tx;                r[s - 1] = tr;            }        }        if(s == 0)        {            cout <<0 <<endl;            continue;        }        h /= 2;  //宽度减半,求区间的 a,b        for(int i = 0; i < s; i ++)        {            q[i].a = x[i] - sqrt(r[i] * r[i] - h * h);            q[i].b = x[i] + sqrt(r[i] * r[i] - h * h);        }        sort(q, q + s, cmp);  //排序        double sum = 0;        int cnt = 0;        while(sum < w)        {            double len = 0;  //当前能覆盖的长度            for(int i = 0; i < s; i ++)  //对每个闭区间判断                if(q[i].a <= sum && q[i].b - len > sum)  //选择满足条件的且最优的                {                    len = q[i].b - sum;                }            if(len == 0)  //有的区间覆盖不到            {                cnt = 0;                break;            }            sum += len;  //覆盖位置后移            cnt ++;  //装置数增加        }        cout <<cnt <<endl;    }    return 0;}        

 

1 0
原创粉丝点击