题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3264
题解:
枚举每个圆的圆心,设起始半径为此圆半径+其他圆(枚举)的直径,然后不断二分,找出满足要求的最小半径。
这里需要一个求两圆相交面积的函数。
计算两圆相交面积:
struct Circle
{
double x, y;
double r;
}cir[100];
double dis(const Circle &a, const Circle &b)
{
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
double calArea(Circle &a, Circle &b)
{
double d = dis(a, b);
if (d >= a.r + b.r)//两圆不相交
return 0;
if (d <= fabs(a.r - b.r)) //两圆内含
{
double r = a.r < b.r ? a.r : b.r;
return acos(-1.0) * r * r;
}
double ang1 = acos((a.r * a.r + d * d - b.r * b.r) / 2. / a.r / d);
double ang2 = acos((b.r * b.r + d * d - a.r * a.r) / 2. / b.r / d);
double ret = ang1 * a.r * a.r + ang2 * b.r * b.r - d * a.r * sin(ang1);
return ret;
}
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const double esp = 1e-8;
int t,n;
struct Circle{
double x, y;
double r;
}cir[100], ori;
double dis(const Circle &a, const Circle &b) {
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
double calArea(Circle &a, Circle &b) {
double d = dis(a, b);
if (d >= a.r + b.r)
return 0;
if (d <= fabs(a.r - b.r)) {
double r = a.r < b.r ? a.r : b.r;
return acos(-1.0) * r * r;
}
double ang1 = acos((a.r * a.r + d * d - b.r * b.r) / 2. / a.r / d);
double ang2 = acos((b.r * b.r + d * d - a.r * a.r) / 2. / b.r / d);
double ret = ang1 * a.r * a.r + ang2 * b.r * b.r - d * a.r * sin(ang1);
return ret;
}
bool check(Circle & a)
{
for(int i = 0 ; i < n; i++)
{
if (calArea(a, cir[i]) * 2 < acos(-1.0) * cir[i].r * cir[i].r)
return false;
}
return true;
};
double bin(double l, double r, Circle& a)
{
double mid;
while (fabs(l - r) >= esp)
{
mid = (l + r) / 2;
a.r = mid;
if (check(a))
{
r = mid;
}
else
{
l = mid + esp;
}
}
return mid;
}
int main()
{
cin >> t;
while(t--)
{
cin >> n;
for(int i = 0; i < n; i++)
cin >> cir[i].x >> cir[i].y >> cir[i].r;
double ans = 1e10;
for(int i = 0; i < n; i++)
{
ori.x = cir[i].x;
ori.y = cir[i].y;
double radius = 0;
for(int j = 0; j < n; j++)
{
radius = max(radius, dis(ori, cir[j]) + cir[j].r);
}
ans = min(ans , bin(0, radius, ori));
}
printf("%.4f\n", ans);
}
return 0;
}