题意:
平面上有n个圆,给定他们各自的圆心和半径。保证任意两个圆不会互相重叠。现在求一个大圆,它的圆心与某个给定圆的圆心重合,且对于每一个给定的圆,大圆至少覆盖该圆面积的一半。请求得满足要求的大圆的最小半径。
算法流程
枚举圆心位置Oi。
二分查找,求得对于当前圆心位置,满足要求的最小半径ri
记录上述所有ri中的最小值,并且输出结果。
时间复杂度
O(n2logn)
注意:只有一个点的情况
CODE:
/*枚举圆心+二分半径*//*AC代码:0ms*/
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#include <cmath>
#define min(a,b) (a<b?a:b)
#define PI 3.14159265358979323
#define eps 1e-7
using namespace std;
struct Node
{
int x,y,r;
double m_area,br;
}node[30];
int N;
double map[30][30];
double ans;
double get_l(int a,int b)
{
double x=node[a].x-node[b].x;
double y=node[a].y-node[b].y;
return sqrt(double(x*x+y*y));
}
void Init()
{
int i,j;
scanf("%d",&N);
for(i=1;i<=N;i++)
{
scanf("%d%d%d",&node[i].x,&node[i].y,&node[i].r);
node[i].m_area=(PI*node[i].r*node[i].r)/2.0;
node[i].br=sqrt(node[i].m_area/PI);
}
for(i=1;i<=N;i++)
{
for(j=i+1;j<=N;j++)
{
map[i][j]=map[j][i]=get_l(i,j);
}
}
}
void swap(double &a,double &b)
{
double t;
if(a<b)
{t=a;a=b;b=t;}
}
//求两圆的相交面(r1>r2,l为向圆心的距离)
double get_area(double r1,double r2,double l)
{
double a1,a2,c1,c2,s1,s2;
swap(r1,r2);
if(l>=r1+r2) return 0;
if(l<=fabs(r1-r2)) return PI*r2*r2;
a2=(l*l+r2*r2-r1*r1)/(2*l);
a1=l-a2;
c1=2*acos(a1/r1);
c2=2*acos(a2/r2);
s1=r1*r1*c1/2-r1*r1*sin(c1)/2;
s2=r2*r2*c2/2-r2*r2*sin(c2)/2;
return s1+s2;
}
bool f(int ith,double mid,int a)
{
double l=map[ith][a];
double r1,r2;
r1=mid;r2=node[a].r;
if(r1<=r2) return false;
if(r1-r2>=l) return true;
double area=get_area(r1,r2,l);
if((area-node[a].m_area)>eps) return true;
return false;
}
bool Judge(int ith,double mid)
{
int i;
bool ok=true;
for(i=1;i<=N;i++)
{
if(i==ith) continue;
if(!f(ith,mid,i))
{ok=false;break;}
}
return ok;
}
void Run(int ith)
{
double l,r,mid;
l=node[ith].br;r=40000;
while(fabs(r-l)>eps)
{
mid=(l+r)/2;
if(Judge(ith,mid))
r=mid;
else
l=mid;
}
ans=min(ans,l);
}
void Solve()
{
int i=1;
ans=70000;
for(i=1;i<=N;i++)
Run(i);
printf("%.4lf\n",ans);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
Init();
Solve();
}
return 0;
}