题目链接:Click here~~
题意:
给你 n 个圆,作一个新的圆(以 n 个圆里面的一个圆心为圆心),要求将所有的圆覆盖至少一半的面积,求出最小半径。
解题思路:
主要是求圆的面积交,之后就可二分了。
大致思路是:用两个扇形的面积 - 四边形的面积。
#include <math.h>
#include <stdio.h>
#include <algorithm>
using namespace std;
const double eps = 1e-6;
const double Pi = acos(-1.0);
struct Point
{
int x,y;
};
struct Circle
{
Point center;
double r;
}A[22];
int n;
int sgn(double x)
{
return x<-eps ? -1 : (x>eps);
}
double Dis(const Point& p1,const Point& p2)
{
return sqrt( 1.0*(p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y) );
}
double Area(const Circle& c)
{
return Pi*c.r*c.r;
}
double CirInter(const Circle& c1,const Circle& c2)
{
double d = Dis(c1.center,c2.center);
if(sgn(d-c1.r - c2.r) >= 0)
return 0;
if(sgn(fabs(c1.r - c2.r)-d) >= 0)
return c1.r<c2.r ? Area(c1) : Area(c2);
double a1 = acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
double a2 = acos((c2.r*c2.r+d*d-c1.r*c1.r)/(2*c2.r*d));
return a1*c1.r*c1.r + a2*c2.r*c2.r - c1.r*d*sin(a1);
}
bool can(double rr)
{
for(int i=0,j;i<n;i++)
{
Circle tmp = A[i];
tmp.r = rr;
for(j=0;j<n;j++)
if(CirInter(tmp,A[j]) < Area(A[j])/2)
break;
if(j == n)
return true;
}
return false;
}
int main()
{
int z;
scanf("%d",&z);
while(z--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d%d%lf",&A[i].center.x,&A[i].center.y,&A[i].r);
double l = 0 , r = 1e6;
while(sgn(r-l) > 0)
{
double mid = (l+r)/2;
if(can(mid))
r = mid;
else
l = mid;
}
printf("%.4f\n",r);
}
return 0;
}