Description
Input
Output
题目大意:给n个互相相离的圆,要求以其中一个圆的圆点为中心,画一个大圆,这个大圆要覆盖这n个圆至少一半的面积,求这个大圆的最小半径。
思路:枚举圆心,二分半径判断是否符合条件即可。
代码(0MS):
1 #include <cstdio> 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 #include <cmath> 6 using namespace std; 7 8 const int MAXN = 25; 9 const double PI = 2 * acos(0.0); 10 const double EPF = 1e-8; 11 12 double x[MAXN], y[MAXN], r[MAXN]; 13 int n, T; 14 15 double dist(double x1, double y1, double x2, double y2) { 16 int xx = x1 - x2, yy = y1 - y2; 17 return sqrt(xx * xx + yy * yy); 18 } 19 20 double fusiform(double a, double c, double b) { 21 double angle = 2 * acos((a * a + b * b - c * c) / (2 * a * b)); 22 double s1 = a * a * PI * (angle / (2 * PI)); 23 double s2 = a * a * sin(angle) / 2; 24 return s1 - s2; 25 } 26 27 bool common(double x1, double y1, double r1, double x2, double y2, double r2) { 28 double d = dist(x1, y1, x2, y2); 29 if(d >= r1 + r2) return false; 30 if(d <= fabs(r1 - r2)) { 31 if(r1 > r2) return true; 32 else return (r1 * r1 * 2 >= r2 * r2); 33 } 34 double value = fusiform(r1, r2, d) + fusiform(r2, r1, d); 35 return value * 2 >= r2 * r2 * PI; 36 } 37 38 bool check(double ox, double oy, double rr) { 39 for(int i = 1; i <= n; ++i) 40 if(!common(ox, oy, rr, x[i], y[i], r[i])) return false; 41 return true; 42 } 43 44 double calc(double ox, double oy) { 45 double l = 0, r = 50000; 46 while(r - l > 1e-6) { 47 double mid = (l + r) / 2; 48 if(check(ox, oy, mid)) r = mid; 49 else l = mid; 50 } 51 return l; 52 } 53 54 void solve() { 55 double ans = 1e100, value; 56 for(int i = 1; i <= n; ++i) { 57 value = calc(x[i], y[i]); 58 ans = min(ans, value); 59 } 60 printf("%.4f\n", ans); 61 } 62 63 int main() { 64 //cout<<PI<<endl; 65 scanf("%d", &T); 66 while(T--) { 67 scanf("%d", &n); 68 for(int i = 1; i <= n; ++i) scanf("%lf%lf%lf", &x[i], &y[i], &r[i]); 69 solve(); 70 } 71 }