题意:是给你一堆点,这些点会形成一个多边形,有两个god站在这个多边形上,他们可以释放一个半径为r的魔法火圈,我们要求的就是两个god放出来的火圈完全覆盖这个多边形时的最小半径。
我的方法是二分半径,然后判断能否覆盖这个多边形是枚举每一条线段,判断每一条线段是否都能被一个圆,或者两个圆完全覆盖,如果能那么这个多边形就能完全被覆盖
其中判断一条跨两个圆的线段能否被两个圆完全覆盖时,用的二分,去找线段上是否存在一个点,同时在两个圆内,如果存在则这条线段能被两个圆完全覆盖。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const double eps=1e-10;
struct P
{
double x,y;
};
struct Line
{
P a,b;
double len;
};
double dis(P a,P b)
{
double c=(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
return sqrt(c);
}
double det(P a,P b,P r)
{
return (a.x-r.x)*(b.y-r.y)-(a.y-r.y)*(b.x-r.x);
}
P qs[100000],r1,r2;
int n;
bool equ(P a,P b)
{
if(fabs(a.x-b.x)<eps && fabs(a.y-b.y)<eps)
return 1;
return 0;
}
bool judge2(Line l,P r1,P r2,double r) //跨两个圆的线段,二分找线段上是否存在一个点,在两个圆内
{
int fg=0;
P a,b,m;
a=l.a;
b=l.b;
while(!equ(a,b))
{
m.x=(a.x+b.x)/2.0;
m.y=(a.y+b.y)/2.0;
if(dis(r1,m)<=r)
a=m;
else
b=m;
if(dis(r1,m)<=r && dis(r2,m)<=r)
{
fg=1;
break;
}
}
return fg;
}
bool judge(double r) //枚举每条线段,看每条线段是否都能被覆盖
{
for(int i=0;i<n-1;i++)
{
for(int j=i+1;j<n;j++)
{
Line l;
l.a=qs[i];
l.b=qs[j];
if(l.a.x>l.b.x)
swap(l.a,l.b);
l.len=dis(l.a,l.b);
double k,e,p,q;
k=dis(l.a,r1);
e=dis(l.b,r1);
p=dis(l.a,r2);
q=dis(l.b,r2);
if(dis(l.a,r1)<=r && dis(l.b,r1)<=r)
continue;
if(dis(l.a,r2)<=r && dis(l.b,r2)<=r)
continue;
if(dis(l.a,r1)<=r && dis(l.b,r2)<=r)
{
if(judge2(l,r1,r2,r))
continue;
}
if(dis(l.b,r1)<=r && dis(l.a,r2)<=r)
{
if(judge2(l,r2,r1,r))
continue;
}
return 0;
}
}
return 1;
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=0;i<n;i++)
scanf("%lf%lf",&qs[i].x,&qs[i].y);
scanf("%lf%lf",&r1.x,&r1.y);
scanf("%lf%lf",&r2.x,&r2.y);
double lf=0.000000000,lr=200000000.000000000;
double md;
while(fabs(lr-lf)>eps)
{
md=(lr+lf)/2.0;
if(judge(md))
lr=md;
else
lf=md;
}
printf("%.3lf\n",md);
}
return 0;
}