主要的思路就是将这个题目转换一下去求。题目上面说,雷达只会在x轴上面,那么我们就可以去算一下大致的几种情况:
第一种,雷达全面覆盖的到。那么转换一下思路。
第二种,存在几个特殊的,比较高的位置,雷达无法覆盖,就是雷达最高为m,但是他的位置高度超过了m,所以直接输出-1.
思路就是我们可以把每一个点转换一下,看成一个圆,去思考一下。如果点可以被覆盖的到,那么圆与x轴就会相交或者相切,以半径为雷达m范围的圆。如果他们不相交,那么就是说雷达扫描不到,因为雷达只在x轴上面。
如图:
在这里我们看见了因为相交的部分不重合,所以要想在x轴上面安雷达覆盖这两个点,我们至少需要两个。
如图的思想,我们再加一个点所构成的圆。在此注明一点就是,在x轴上面的范围就是表明雷达如果要覆盖这点,那么他就必须在这个范围里面。因为二点,一必须在x轴上面,二他是以雷达范围的圆,不在就说明点与雷达的范围超过了雷达扫描的范围。
在此图,我们可以更好的看出如果,范围重合了,就说明他们可以用一个雷达去扫描得到。
最后得到的其实就是这个图了,求的就是公共覆盖的就用一点,不是公共覆盖的就开辟,把一个范围不断的缩小,缩小的区域就是共同的雷达,不在缩小的区域类,就代表着,存在一点和你不含有公共区域。
所以题目的思路就清晰了,先把点转化为在x轴上面的范围,求范围的话,根据数学的公式就可以求出来了。[x-根号下(r*r-y*y),x+根号下(r*r-y*y)],这个范围就可以了。最后题目就转换成了求公共覆盖范围用一个雷达,不在就新建一个雷达。
既然我要用一个圆尝试着(雷达范围,半径为r)去覆盖岛屿,那为何不以岛屿为圆心r为半径画一个圆(记为圆O),于是只要雷达在这个圆里那么这个岛屿就能被覆盖。而从前面的分析可知,雷达必然要布置在x轴上,所以雷达肯定放在圆O与x轴的那段交线区间上,如图:
所以我们可以将所有的岛屿对应的这段区间记录下来,然后以区间左界从小到大排序就行,之后从第一个区间开始,如果第二个区间与其有交集,就更新这个交集,并从队列中除去区间1,2,如果第三个区间与这个交集又有交集,那么便更新交集并除去区间3直到不满足有交集为止。然后继续模拟这个过程就行了,每模拟以此这个过程ANS++(即区间选点问题)
但是这道题注意浮点误差!以及sqrt(double)的使用
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<iostream>
#define MAXN 1010
using namespace std;
struct node
{
double xl;//最左可被侦测坐标
double xr;//最右可被侦测坐标
}island[MAXN];
int n,d,x,y,cnt,flag;
double offset;
bool cmp(node a,node b)
{
return a.xl<b.xl;
}
int find()
{
int num=0;
double cur; //当前最右可被侦测坐标
cur=island[1].xr;
num++;
for(int i=2;i<=n;i++)
{
if(island[i].xl-cur>1e-6) //下个岛屿的最左坐标大于当前最右可被侦测坐标
{
num++;
cur=island[i].xr;
}
else
if(island[i].xr-cur<1e-6) //下个岛屿的最右坐标小于当前最右可被侦测坐标
cur=island[i].xr;
}
return num;
}
int main()
{
while(~scanf("%d %d",&n,&d))
{
if(n==0&&d==0)break;
flag=0;
cnt++;
for(int i=1;i<=n;i++)
{
scanf("%d %d",&x,&y);
if(y>d) flag=1;
offset=sqrt((double)(d*d-y*y));
island[i].xl=x-offset;
island[i].xr=x+offset;
}
if(flag)
{
printf("Case %d: -1\n",cnt);
continue;
}
sort(island+1,island+n+1,cmp);
int ans=find();
printf("Case %d: %d\n",cnt,ans);
}
return 0;
}