n个半径为R的圆是否有公共部分,等价于询问是否存在一个半径小于R的圆,能覆盖所有n个圆的圆心。
对这n个点求最小圆覆盖即可。从网上扒了个随机增量法的代码。
这样算上二分,复杂度就是nlogn了。
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const double eps=0.000000001;
int n;
double V,x[103],y[103],dx[103],dy[103],v[103],cx[103],cy[103];
struct node
{
double x,y;
};
node p[1000001];
double r;
node O;
double dist(node a,node b)
{
return sqrt( (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y) );
}
void calc(double a,double b,double c,double d,double e,double f)
{
O.y=(c*d-f*a)/(b*d-e*a);
O.x=(c*e-f*b)/(a*e-b*d);
}
double get()
{
for (int i=1;i<=n;++i)
{
p[i].x=cx[i];
p[i].y=cy[i];
}
O=p[1];r=0;
for(int i=2;i<=n;++i)
if(dist(O,p[i])>r+1e-6)
{
O=p[i];r=0;
for (int j=1;j<=i-1;++j)
if (dist(O,p[j])>r+1e-6)
{
O.x=(p[i].x+p[j].x)/2;
O.y=(p[i].y+p[j].y)/2;
r=dist(O,p[j]);
for (int k=1;k<=j-1;++k)
if (dist(O,p[k])>r+1e-6)
{
calc(p[j].x-p[i].x,p[j].y-p[i].y,(p[j].x*p[j].x+p[j].y*p[j].y-p[i].x*p[i].x-p[i].y*p[i].y)/2,
p[k].x-p[i].x,p[k].y-p[i].y,(p[k].x*p[k].x+p[k].y*p[k].y-p[i].x*p[i].x-p[i].y*p[i].y)/2);
r=dist(O,p[k]);
}
}
}
return r;
}
bool check(double t)
{
for(int i=1;i<=n;++i)
{
cx[i]=x[i]+dx[i]*t*v[i];
cy[i]=y[i]+dy[i]*t*v[i];
}
return get()<t*V+eps;
}
int main()
{
while(scanf("%d%lf",&n,&V)!=EOF)
{
for(int i=1;i<=n;++i)
{
scanf("%lf%lf%lf%lf%lf",&x[i],&y[i],&dx[i],&dy[i],&v[i]);
double l=sqrt(dx[i]*dx[i]+dy[i]*dy[i]);
dx[i]/=l;
dy[i]/=l;
}
double l=0,r=9999999;
while(l<r-eps)
{
double mid=(l+r)*0.5;
if(check(mid)) r=mid;
else l=mid;
}
printf("%.4lf\n",r);
}
return 0;
}