一本通p1424 喷水装置

Posted huixinxinw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一本通p1424 喷水装置相关的知识,希望对你有一定的参考价值。

1424:【例题3】喷水装置

题目链接:http://ybt.ssoier.cn:8088/problem_show.php?pid=1424

时间限制: 1000 ms 内存限制: 65536 KB
提交数: 2578 通过数: 407
【题目描述】
长 L 米,宽 W 米的草坪里装有 n 个浇灌喷头。每个喷头都装在草坪中心线上(离两边各 W2 米)。我们知道每个喷头的位置(离草坪中心线左端的距离),以及它能覆盖到的浇灌范围。

请问:如果要同时浇灌整块草坪,最少需要打开多少个喷头?

【输入】
输入包含若干组测试数据。

第一行一个整数 T 表示数据组数;

每组数据的第一行是整数 n、L 和 W;

接下来的 n 行,每行包含两个整数,给出一个喷头的位置和浇灌半径(上面的示意图是样例输入第一组数据所描述的情况)。

【输出】
对每组测试数据输出一个数字,表示要浇灌整块草坪所需喷头数目的最小值。如果所有喷头都打开也不能浇灌整块草坪,则输出 ?1 。

分析

对于每一个喷头我们知道他的浇灌半径(如图中红线所示),又已知草坪宽度的一般(如图中绿线),那么我们可以利用勾股定理求出图中蓝线的长度。

喷头位置减去蓝线长度为喷头所能覆盖到的左端点,喷头位置减去蓝线为右端点。

要注意的一点是,如果圆形的半径小于等于w/2就无法浇灌到任何一段位置,在读入数据的时候要进行特判

技术图片

确定好每个喷头所覆盖的左右两个端点以后,我们按照左端点由小到大排序。

用一个指针记录最左边还未被覆盖的位置,在能覆盖到指针所在位置的喷头中,我们采取贪心的策略,选择其中右端点最远的一个喷头,并将指针所指的位置更新为其右端点的位置,直到整个草坪被完全覆盖。

如果指针记录的位置没有任何一个喷头能够那么就输出-1

(划重点)因为涉及到根号的运算,端点位置要用double类型来存储qwq

(因为没用double改了两个多小时。。。(肥宅暴风雨哭泣

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath> 
#include<cstring>
#include<string> 
using namespace std;
int read(){
    int a = 0,f= 0;char p= getchar();
    while(!isdigit(p)){f|=p=='-';p = getchar();}
    while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p = getchar();}
    return f?-a:a;
}//快读
struct qwq{
    double ll,rr;
}p[100000];//结构体来存储每个喷头浇灌的两个端点位置
bool cmp(qwq a,qwq b){
    return a.ll < b.ll;
}//按照左端点排序
bool flag[100000];
int main(){
    int t;
    t = read();
    while(t--){
        int cnt = 0; 
        memset(p,0,sizeof(p));//读入多组数据别忘了清空数组
        memset(flag,0,sizeof(flag));
        int n,L;
        double w;
        n = read();
        L = read();
        w = read();
        double wz,rr;
        for(int i = 1;i <= n;i ++){
            wz = read();
            rr = read();
            if(rr <= w/2)continue;//半径小于w/2的情况就跳过
            cnt ++;
            p[cnt].ll = wz - sqrt(rr*rr-(w/2)*(w/2));
            p[cnt].rr = wz + sqrt(rr*rr-(w/2)*(w/2));
        }
        sort(p + 1,p + cnt + 1,cmp);
        double l = 0,ans = 0;//用来记录当前所浇水浇到了哪里。
        int bj; 
        p[cnt+1].ll=2147483040;//要考虑最后一个喷头
        for(int i = 1;i <= cnt + 1 ;i++){
            if(l >= L)break;//都能浇灌上
            bj = 0;
            if(p[i].ll > l){//找到第一个覆盖不住当前左端点的点
                for(int j = i-1;j >= 1;j --){//这个点之前的点一定能覆盖到指针位置
                    if(!flag[j] && p[j].rr > l){//如果右端点大于指针位置
                        bj = j;
                        l = p[j].rr;
                    }
                }
                //cout<<bj<<" "<<l<<endl;
                if(bj == 0){cout << -1<<endl;break;}//指针位置没有喷头能覆盖到
                flag[bj] = 1;//更新指针
                ans++;//又多了一个喷头
            } 
        }
        if(bj != 0)cout << ans<<endl;//输出答案
    }
}

以上是关于一本通p1424 喷水装置的主要内容,如果未能解决你的问题,请参考以下文章

喷水装置2 贪心

贪心问题 区间覆盖 —— 喷水装置

南阳OJ-12-喷水装置贪心+区间覆盖

喷水装置-区间贪心

nyoj 6 喷水装置

喷水装置 贪心算法