长 LL米,宽 W 米的草坪里装有 n 个浇灌喷头。每个喷头都装在草坪中心线上(离两边各 W/2米)。我们知道每个喷头的位置(离草坪中心线左端的距离),以及它能覆盖到的浇灌范围。
请问:如果要同时浇灌整块草坪,最少需要打开多少个喷头?
输入格式
输入包含若干组测试数据。
第一行一个整数 T表示数据组数;
每组数据的第一行是整数 n、L 和 W;
接下来的 n 行,每行包含两个整数,给出一个喷头的位置和浇灌半径(上面的示意图是样例输入第一组数据所描述的情况)。
输出格式
对每组测试数据输出一个数字,表示要浇灌整块草坪所需喷头数目的最小值。如果所有喷头都打开也不能浇灌整块草坪,则输出 -1 。
**解析:**首先将喷头能喷到的范围看成一条线段,若喷头半径小于w/2,则直接舍弃,
然后按照线段的开始点给喷头排序,并保证每次选用灌溉范围大的喷头。
#include <bits/stdc++.h>
using namespace std;
struct L
{
double left,right;
}l[15005];
int cmp(L q,L p)
{
return q.left<p.left;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n,m,w,a,b,ans=0,flag,d=0;
double c,x,sum=0,y,e=0;
scanf("%d%d%d",&n,&m,&w);
for(int i=0;i<n;++i){
scanf("%d%d",&a,&b);
if(b<w*1.0/2){
i--;
n--;
continue;
}
else{
y=(double)b*b-(double)w/2*w/2;
c=sqrt(y);
l[i].left=a-c;
l[i].right=a+c;
if(l[i].right>e){ //记录喷头能到达的最右边界
e=l[i].right;
}
}
}
sort(l,l+n,cmp);
if(e<m){
printf("-1\n"); //若最右边没到达末尾,则结束
continue;
}
while(sum<m){ //sum是目前覆盖的最右边
x=0; //代表比前一个装置能够覆盖的范围往右延长的最大值
flag=0;
for(int j=d;j<n && l[j].left<=sum;j++){ //保证该线段与sum有相交或相接
if((l[j].right-sum)>x){
x = l[j].right-sum;
d=j;
flag=1;
}
}
if(flag==0){
break;
}
else{
sum+=x;
ans++;
}
}
if(flag==0){
printf("%d\n",-1);
}
else{
printf("%d\n",ans);
}
}
return 0;
}