喷水装置(二)
时间限制:
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
-
解题思路:该题是一个区间覆盖问题,把面积上的覆盖转化为线段上的覆盖,例如一个喷水装置,它的
中心在4,喷水半径为5,草坪的宽度为6,sqrt(5*5-6*6/4)=4,则在区间(4-4,4+4)的位置都可以被覆
盖,将这一系列的都转化为相应的区间,并将区间按照从起始位置按小到大排序,其中不成立的有两种情况 -
1.中间有没有覆盖的
-
2.最后没有覆盖完全
代码如下:
-
# include<stdio.h> # include<math.h> # include<algorithm> using namespace std; struct node{ double x; double y; }a[10005]; bool cmp(node a,node b) { return a.x<b.x; } int main(){ int t; scanf("%d",&t); while(t--) { int n,w,h; scanf("%d%d%d",&n,&w,&h); int c1,c2,j=0; double k=h*h*1.0/4; for(int i=0;i<n;i++) { scanf("%d%d",&c1,&c2); if(2*c2>h) { a[j].x=c1-sqrt(c2*1.0*c2-k); a[j].y=c1+sqrt(c2*1.0*c2-k); j++; } } sort(a,a+j,cmp); int count=0,k1; double k2=0; for(int i=0;i<j;i++) { int k3=0; k1=0; while(i<j&&a[i].x<=k2) //关键代码,画一下图就明白这个的意思了 { k1=1; if(a[i].y>k3) k3=a[i].y; i++; } count++; i--; k2=k3; if(!k1) break; if(k2>=w) break; } if(k1&&k2>=w) printf("%d\n",count); else printf("0\n"); } return 0; }
-
-
第一行输入一个正整数N表示共有n次测试数据。