1.1.3

· · 个人记录

喷水装置

【题目描述】

  长 L 米,宽 W 米的草坪里装有 n 个浇灌喷头。每个喷头都装在草坪中心线上(离两边各 W2 米)。我们知道每个喷头的位置(离草坪中心线左端的距离),以及它能覆盖到的浇灌范围。

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

  

  算法:贪心

  我们先算出每个喷头真正有效的喷水范围S=sqrt(pow(r,2)-pow(w/2,2)),然后以左端点升序排列[若断层则break],每次选择右端点最右边的合法的点。——J(L)X(J)C(H)大佬已经证明其正确性。

#include<bits/stdc++.h>
using namespace std;
struct L{
    double lft,rgt;
    int r,wz;
}a[100010];
bool cmp(L a,L b){return a.lft<b.lft;}
int l,w,n,t;
inline double getlft(int x){double xx=((double)((double)w/2))*((double)((double)w/2));double yy=((double)(a[x].r))*((double)(a[x].r));return (double)((double)a[x].wz-(double)sqrt(yy-xx));}
inline double getrgt(int x){double xx=((double)((double)w/2))*((double)((double)w/2));double yy=((double)(a[x].r))*((double)(a[x].r));return (double)((double)a[x].wz+(double)sqrt(yy-xx));}
int main(){
    scanf("%d",&t);
    while(t--){
        double now=0;int ans=0;
        scanf("%d%d%d",&n,&l,&w);
        for(int i=1;i<=n;i++){
            scanf("%d%d",&a[i].wz,&a[i].r);
            if((double)a[i].r<=(double)((double)w/2)){i--,n--;continue;}
            a[i].lft=getlft(i),a[i].rgt=getrgt(i);
        }
        sort(a+1,a+n+1,cmp);
        if(a[1].lft>0){puts("-1");continue;}
        while(now<l) 
        {
            double m=0;
            for(int i=1;i<=n&&a[i].lft<=now;i++)
            if(a[i].rgt-now>m)m=a[i].rgt-now;
            if(m!=0)ans++,now+=m;else break;
        }
        if(now<w)puts("-1");
        else cout<<ans<<'\n';
    }
    return 0;
}