题意:N(1<=N<=20) 个圆,现取其中一个圆的圆心为圆心作一个大圆,使得这个大圆与其他任意一个圆 c 的面积交 >= c 的面积的一半,求大圆的最小半径。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3264
——>>枚举圆心,二分半径。。
#include <cstdio>
#include <cmath>
#include <algorithm>
using std::min;
const double EPS = 1e-8;
const double PI = acos(-1.0);
const int MAXN = 20 + 10;
int N;
double harea[MAXN];
int Dcmp(double x)
{
if (fabs(x) < EPS) return 0;
return x > 0 ? 1 : -1;
}
struct POINT
{
double x;
double y;
POINT(double x = 0.0, double y = 0.0) : x(x), y(y) {}
};
typedef POINT VECTOR;
struct CIRCLE
{
POINT c;
double r;
CIRCLE() {}
CIRCLE(POINT c, double r) : c(c), r(r) {}
} mall[MAXN];
double Length(POINT A, POINT B)
{
return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y));
}
// 两圆面积交
double AreaCircleCircle(CIRCLE c1, CIRCLE c2)
{
double ret = 0.0;
double d = Length(c1.c, c2.c);
if (Dcmp(d - c1.r - c2.r) < 0 && Dcmp(d - fabs(c1.r - c2.r)) > 0)
{
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);
ret = (a1 - sin(2 * a1) / 2) * c1.r * c1.r + (a2 - sin(2 * a2) / 2) * c2.r * c2.r;
}
else if (Dcmp(d - fabs(c1.r - c2.r)) <= 0)
{
if (Dcmp(c1.r - c2.r) < 0)
{
ret = PI * c1.r * c1.r;
}
else
{
ret = PI * c2.r * c2.r;
}
}
return ret;
}
void Read()
{
scanf("%d", &N);
for (int i = 0; i < N; ++i)
{
scanf("%lf%lf%lf", &mall[i].c.x, &mall[i].c.y, &mall[i].r);
harea[i] = PI * mall[i].r * mall[i].r / 2;
}
}
bool IsOk(const POINT& center, const double& r)
{
for (int i = 0; i < N; ++i)
{
if (Dcmp(AreaCircleCircle(CIRCLE(center, r), mall[i]) - harea[i]) < 0)
{
return false;
}
}
return true;
}
void Solve()
{
double ret = 34000.0;
for (int i = 0; i < N; ++i)
{
double L = 0.0;
double R = 34000.0;
while (Dcmp(L - R) < 0)
{
double M = (L + R) / 2;
IsOk(mall[i].c, M) ? R = M : L = M;
}
ret = min(ret, L);
}
printf("%.4f\n", ret);
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
Read();
Solve();
}
return 0;
}