UVA-10382经典贪心问题,区间覆盖

题目链接https://vjudge.net/problem/UVA-10382

题目大意:有一块草坪,长为l,宽度为w.在其中心线的不同位置处装有n个点状喷水装置,每个喷水装置i,都可以把以他为中心半径为r的区域湿润,给你一些喷水装置,请选择尽量少的喷水装置,把整个草坪湿润。

思路:每个喷水装置就是一个圆,由于必须完全覆盖草坪,所以对于每个喷水装置只需要关注圆与草坪边缘交点,就可以了,所以对于每个喷水装置,转化为每个一个矩形,如图:

所以,可以把每个喷水装置装化为,一个矩形,求出矩形的左右坐标 l  r,然后就可以转化为,几个区间求覆盖问题;具体如下:对所有区间的  l  进行排序,维护两个值   left   right  刚开始记录为0;在所有左边界小于left的区间找到最大的r,更新right为r,然后把left更新为r;不断更新right和left当right大于总长度时就可以跳出,输出答案了,代码如下:

#include<bits/stdc++.h>
using namespace std;

int n,l,w;

struct node
{
    double left,right;
}wt[10010];
bool cmp(node a,node b)
{
    return a.left<b.left;
}
int main()
{
    while(~scanf("%d%d%d",&n,&l,&w))
    {
        double p,r;
        int cnt=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf",&p,&r);
            if(r<=w/2.0)
                continue;
            double x1=sqrt(r*r-w*w/4.0);
            wt[cnt].left=p-x1;
            wt[cnt].right=p+x1;
            cnt++;
        }
        sort(wt,wt+cnt,cmp);
        double left=0,right=0;
        int ans=0,flag=0;
        if(wt[0].left<=0)
        {
            int i=0,j;
            while(i<cnt)
            {
                j=i;
                while(j<cnt&&left>=wt[j].left)
                {
                    if(wt[j].right>right)
                        right=wt[j].right;
                    j++;
                }
                if(j==i)
                    break;
                ans++;
                left=right;
                i=j;
                if(left>=l)
                {
                    flag=1;
                    break;
                }
            }
        }
        if(flag)
            printf("%d\n",ans);
        else
            cout<<"-1"<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/KXL5180/article/details/82824003
今日推荐