Watering Grass(区间覆盖+贪心)

n sprinklers are installed in a horizontal strip of grass l meters long and w meters wide. Each sprinkler is installed at the horizontal center line of the strip. For each sprinkler we are given its position as the distance from the left end of the center line and its radius of operation. What is the minimum number of sprinklers to turn on in order to water the entire strip of grass?

Input    Input consists of a number of cases. The first line for each case contains integer numbers n, l and w with n ≤ 10000. The next n lines contain two integers giving the position of a sprinkler and its radius of operation. (The picture above illustrates the first case from the sample input.)

Output  For each test case output the minimum number of sprinklers needed to water the entire strip of grass. If it is impossible to water the entire strip output ‘-1’.

Sample Input

8 20 2

5 3

4 1

1 2

7 2

10 2

13 3

16 2

19 4

3 10 1

3 5

9 3

6 1

3 10 1

5 3

1 1

9 1

Sample Output

6

2

-1

题意:有一个长为l宽为w的草坪,草坪中心轴上有n个喷水装置,给出喷泉所在位置(圆心)以及所喷水的半径,想要覆盖整个草坪,最少需要多少个喷泉装置?

题解:区间覆盖+贪心,计算出每个装置所能覆盖的以草坪的宽为宽度的最大矩形的最左端a和最右端b,区间[a,b]就是能够覆盖的其中一个区间,使所找各个区间无缝衔接,能够使草坪完全覆盖。对所有满足矩形区间的左端点从小到大进行排序,每次所找区间能够与已经覆盖的区间衔接,并且右区间的值最大,直到右区间完全覆盖整个草坪,此时就得到喷泉装置的最小值。

 下面AC代码:

#include <iostream>
#include <string.h>
#include <algorithm>
#include <cmath>
#include <map>
using namespace std;

struct jgt   //将区间存入结构体中
{
    double a,b;  //a为左区间,b为右区间
} s[10005];

bool cmp(jgt x,jgt y)
{
    return x.a<y.a;//以左区间的大小进行排序
}

int main()
{
    int n,l,w;
    while(cin>>n>>l>>w)
    {
        double x,y,len=0;
        int le=0,sum=0;
        for(int i=1; i<=n; i++)
        {
            cin>>x>>y;
            if(2*y<w)  //如果喷泉所喷草坪的直径小于草坪宽度,说明无法覆盖草坪,无法计算覆盖区间,跳过本次循环
            {
                continue;
            }
            else
            {
                len=sqrt(y*y-w*w/4.0);//使用勾股定理去求能够完全包含的长度
            }
            s[++le].a=x-len;  //左区间的值
            s[le].b=len+x;   //右区间的值
        }
        sort(s+1,s+le+1,cmp); //按照由小到大排序
        double c1=0,c2=0;//初始化左右区间端点
        bool pp=1;//标记是否符合题意

        while(c2<l)//区间小于草坪长度循环继续,如果大于草坪长度l说明喷泉已经够了,结束while循环
        {
            c1=c2;   //每循环一次将c2赋值于c1,此时c1为下一个区间的左端点,从原c2点开始无缝衔接
            for(int i=1; i<=le; i++)
            {
                if(s[i].a<=c1&&s[i].b>c2)  //如果此时的左端点s[i].a是小于c1的,说明此时草坪一直到c1都能被覆盖,此时s[i].b是大于c2
                {
                    c2=s[i].b;  //s[i].b所存的是右区间的值,此时将s[i].b赋值于c2,这时草坪可覆盖到c2                }

                }
            }
            if(c1==c2&&c1<l)  //如果此时c1==c2,c1小于草坪的长度l说明无法完全覆盖草坪
            {
                pp=0;  //不符合题意,标记pp为0
                break;
            }
            sum++;
        }
        if(pp==0) cout<<"-1"<<endl;//不符合题意
        else cout<<sum<<endl;  //输出sum的值
    }

    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值