题目链接:
HDU 3264 Open-air shopping malls
题意:
给出n个圆的圆心和半径,以这些圆的某个圆圆心为圆心画一个半斤为R的圆,使得这个半径为R的圆覆盖这n个圆每个圆的面积至少一半,求出最少的R.
n<=20.
分析:
枚举圆心,二分查找最小半径。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <climits>
#include <cmath>
#include <ctime>
#include <cassert>
#include <iomanip>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int MAX_N = 30;
int T, n;
struct Circle{
double x, y, r, ans;
}circle[MAX_N];
inline bool check(double R, double r, double d)
{
if(R <= d) return false;
if(R >= d + r) return true;
double a1 = acos((r * r + d * d - R * R) / (2 * r * d));
double a2 = acos((R * R + d * d - r * r) / (2 * R * d));
double s1 = a1 * r * r + a2 * R *R - r * d * sin(a1);
double s2 = 0.5 * pi * r * r;
return s1 + eps >= s2;
}
inline double GetRadius(int i, int j)
{
double d = hypot(circle[i].x - circle[j].x, circle[i].y - circle[j].y);
double r = circle[j].r;
double high = 1e7, low = 0;
for(int i = 0; i < 100; i++){
double mid = (high + low) / 2;
if(check(mid, r, d) ) high = mid;
else low = mid;
}
return high;
}
inline double work(int k)
{
double res = -1;
for(int i = 0; i < n; i++){
if(i == k) continue;
res = max(res, GetRadius(k, i));
}
return res;
}
int main()
{
freopen("E.in", "r", stdin);
IOS;
cin >> T;
while(T-- > 0){
cin >> n;
for(int i = 0; i < n; i++){
cin >> circle[i].x >> circle[i].y >> circle[i].r;
}
if(n == 1){
double res = 0.70710678 * circle[0].r;
cout << fixed << setprecision(4) << res << endl;
continue;
}
double res = 1e7;
for(int i = 0; i < n; i++){
circle[i].ans = work(i);
res = min(res, circle[i].ans);
}
cout << fixed << setprecision(4) << res << endl;
}
return 0;
}