codeforces round514 D Natural reserve(简单几何+二分)

xiaoxiao2025-10-24  5

题意

坐标轴中有 n n n个点,需要画一个圆,这个人与 x x x轴相切,且包含全部的 n n n个点,问这个圆的半径最小是多少。

题解

二分搜索半径,观察可以发现,这个圆的圆心一定是在 y = R y = R y=R上面移动的,所以我们可以依据这个半径确定每个点的圆心在 y = R y=R y=R这条线上的范围,如果所有的点的圆心的范围有交集,那么这个 R R R就是符合条件的。 对于一个点,其可能的圆心范围是 l = x − R 2 − ( y − R ) 2 , r = l = x + R 2 − ( y − R ) 2 l = x-\sqrt{R^2-(y-R)^2}, r =l = x+\sqrt{R^2-(y-R)^2} l=xR2(yR)2 ,r=l=x+R2(yR)2 ,需要判断一下根号下为负数的情况,还有直接 R ∗ R R*R RR会爆精度,需要化简一下。

代码

#include <iostream> #include <cmath> using namespace std; const int maxn = 1e5+5; const double EPS = 1e-8; int n; struct Node { double x,y; }cor[maxn]; bool ok(double x) { double l = -1e10, r = 1e10; for(int i = 0; i < n; ++i) { double h = abs(cor[i].y-x); if(h > x) return 0; double range = sqrt(cor[i].y*(2*x-cor[i].y)); l = max(l, cor[i].x-range), r = min(r, cor[i].x+range); } return (r-l)>EPS; } int main() { scanf("%d", &n); bool fg1 = false, fg2 = false; for(int i = 0; i < n; ++i) { scanf("%lf%lf", &cor[i].x, &cor[i].y); if(cor[i].y < 0) fg1 = true, cor[i].y = -cor[i].y; else fg2 = true; } if(fg1 && fg2) { puts("-1"); } else if(n == 1) { printf("%lf\n", cor[0].y/2); } else { double l = 0, r = 1e18, ans; for(int i = 0; i < 1000; ++i) { double mid = (l+r)/2; // cout << mid << endl; if(ok(mid)) { r = mid; ans = mid; } else l = mid; } printf("%lf\n", ans); } return 0; }
转载请注明原文地址: https://www.6miu.com/read-5038433.html

最新回复(0)