喷水装置(二)
时间限制:
3000 ms | 内存限制:
65535 KB
难度:
4
-
描述
-
有一块草坪,横向长w,纵向长为h,在它的橫向中心线上不同位置处装有n(n<=10000)个点状的喷水装置,每个喷水装置i喷水的效果是让以它为中心半径为Ri的圆都被润湿。请在给出的喷水装置中选择尽量少的喷水装置,把整个草坪全部润湿。
-
输入
-
第一行输入一个正整数N表示共有n次测试数据。
每一组测试数据的第一行有三个整数n,w,h,n表示共有n个喷水装置,w表示草坪的横向长度,h表示草坪的纵向长度。
随后的n行,都有两个整数xi和ri,xi表示第i个喷水装置的的横坐标(最左边为0),ri表示该喷水装置能覆盖的圆的半径。
输出
-
每组测试数据输出一个正整数,表示共需要多少个喷水装置,每个输出单独占一行。
如果不存在一种能够把整个草坪湿润的方案,请输出0。
样例输入
-
2 2 8 6 1 1 4 5 2 10 6 4 5 6 5
样例输出
-
1
2
-
-
代码:
-
-
#include<stdio.h> #include<string.h> #include<math.h> #include<algorithm> using namespace std; int x[100010],r[100010];//x表示喷水装置坐标,r表示覆盖半径 struct record { double start;//每个喷水装置覆盖范围的起点 double end;//覆盖范围的终点 }num[100010]; bool cmp(record a,record b) { if(a.start!=b.start) return a.start<b.start; else return a.end>b.end; }//按起点升序排列,如果起点相同,按终点降序排列 int main() { int T,n,w,h,i,j,k,l,f,g,contact,sum;//sum计数,contact表示接上一装置且最优的装置。 double he,chang;//chang表示两个相邻喷水装置的终点之差,he表示当前喷水装置所能覆盖的长度 scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&w,&h); f=0,g=0,k=0; for(i=0;i<n;i++) { scanf("%d%d",&x[i],&r[i]); if(r[i]>(double)h/2) { num[k].start=x[i]-sqrt(r[i]*r[i]-(double)h*h/4); if(num[k].start<0) { num[k].start=0; } num[k].end=x[i]+sqrt(r[i]*r[i]-(double)h*h/4); if(num[k].start==0) f=1; if(num[k].end>=w) g=1; k++; } } if(f==0||g==0) printf("0"); else { sort(num,num+k,cmp); sum=0,contact=1; for(i=0;i<k;i+=(contact-i)) { chang=0; l=0; he=num[i].end; sum++; if(he>=w) break; for(j=i+1;j<k;j++) { if((num[j].start<=num[i].end)&&(num[j].end-num[i].end>chang)) { chang=num[j].end-num[i].end; contact=j; l=1; } } if(l==0) break; } if(he>=w) printf("%d",sum); else printf("0"); } printf("\n"); } return 0; }
-
第一行输入一个正整数N表示共有n次测试数据。