NYOJ 12 喷水装置(二)

题目链接 http://acm.nyist.net/JudgeOnline/problem.php?pid=12

题目

描述

有一块草坪,横向长w,纵向长为h,在它的橫向中心线上不同位置处装有n(n<=10000)个点状的喷水装置,每个喷水装置i喷水的效果是让以它为中心半径为Ri的圆都被润湿。请在给出的喷水装置中选择尽量少的喷水装置,把整个草坪全部润湿。

输入

第一行输入一个正整数N表示共有n次测试数据。
每一组测试数据的第一行有三个整数n,w,h,n表示共有n个喷水装置,w表示草坪的横向长度,h表示草坪的纵向长度。
随后的n行,都有两个整数xi和ri,xi表示第i个喷水装置的的横坐标(最左边为0),ri表示该喷水装置能覆盖的圆的半径。


样例输入:
2
2 8 6
1 1
4 5
2 10 6
4 5
6 5

输出

每组测试数据输出一个正整数,表示共需要多少个喷水装置,每个输出单独占一行。
如果不存在一种能够把整个草坪湿润的方案,请输出0。


样例输出:
1
2

解题思路

  • 题目意思就是在[0,w]区间上,尽可能少的用给出的固定区间填满。给出的喷头坐标与半径需要转换以存储方便使用
  • 贪心算法
  • 遍历数组寻找一个左边在起点b左边并且右边界最大的区间maxR,找到以后就将这个右边界作为新的起点b,循环,直到maxR>=w

代码(C++)

#include <bits/stdc++.h>
using namespace std;
const int M = 10000+5;
struct pen{                 //定义区间结构体,元素l,r分别为区间的左右边界
    double l,r;
};
int main(){
    pen a[M] = {0};
    int N;
    cin>>N;
    while(N--){
        int n,w,h;
        cin>>n>>w>>h;
        for(int i=0;i<n;i++){//读入x,r 并将其转化后存入数组中
            int x,r;
            cin>>x>>r;
            double z = 0;
            //若喷头的纵向不能达到边界,则其区间长度为零,不影响后边的使用
            if(r>h/2.0)      
                z = sqrt(r*r-h*h/4.0);
            a[i].l = x-z;
            a[i].r = x+z;
        }
        double b=0,maxR=0;
        int cnt=0,flag=0;
        while(b<w){
            //遍历数组,找到左边界在起点左边、有边界在起点右边的右边界最大的最大值,存入maxR
            for(int j=0;j<n;j++){
                if(a[j].l<=b && a[j].r>=b){
                    maxR = maxR>a[j].r?maxR:a[j].r;
                }
            }
            //若没找到更大的,说明不能在往右延伸了,方案不存在,输出0结束测试
            if(b == maxR){      
                cout << 0 << endl;
                flag = 1;
                break;
            }
            b = maxR;
            cnt++;
        }
        if(!flag)
            cout << cnt <<endl;
    }
}

运行结果

ResultAccepted
Time4Ms
Memory264
LanguageG++
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值