喷水装置(二)
时间限制:
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
-
第一行输入一个正整数N表示共有n次测试数据。
/*
*自己不太会做这种题,测试了好多册都没成功,还好网上找了一片很符合自己想法的
*下面把思路说下:
*题目只给 x坐标还有圆半径,也就是说 半径小于 矩形高度一般的就不用考虑,然后将获取的有用数据放入数组
* 考虑区间划分友三种情况如下
区间覆盖问题分成三种情况(“---”表示区间) 第一种情况 a ----------- b -------------- c ----------- 此时没有能覆盖b和c之间的区域 第二种情况 a ----------- b ------------ c ------------- 此时需要选择a,b,c三个区间 第三种 a ----------- b ------------- c ---------------
按照渐近原则 第一个圆左边界应该(此时左边界在矩形外)要最靠近矩形(题目要求“用最少的装置”) 且圆右边界尽量长 所以要先循环找出最此圆
for(i->n)
if(p[i].l <= left && maxr < p[i].r )
maxr = p[i].r
其后圆的测试方法 和上面相同。
*/
#include <iostream>
using namespace std;
#include<cmath>
#include <cstdio>
struct point
{
float l,r;
}p[10005];
int main(int argc, char *argv[])
{
float w,h,s,x1,x,r,x2;
int i,n,ans;
int kase;
scanf("%d",&kase);
while (kase--)
{
scanf("%d%f%f",&n,&w,&h);
i=0;h=h/2;
while (n--)
{
scanf("%f%f",&x,&r);
if (r>=h)
{
s=sqrt(r*r-h*h);
x1=x-s;
x2=x+s;
p[i].l=x1;
p[i++].r=x2;
}
}
//在执行下面程序时,个人认为应该先排序这样循环次数会少
n=i;ans=0;
float start=0,end=w,maxr;
while(start<end)
{ maxr=0;
for(i=0;i<n;i++) //程序可以优化 当第i个圆找到时,后面圆的位置可直接i+1
if(p[i].l<=start&&p[i].r>maxr)
maxr=p[i].r;
if(maxr==start) {ans=0;break;}
ans++;
start=maxr;
}
cout<<ans<<endl;
}
return 0;
}