题意
坐标轴中有 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=x−R2−(y−R)2,r=l=x+R2−(y−R)2,需要判断一下根号下为负数的情况,还有直接
R
∗
R
R*R
R∗R会爆精度,需要化简一下。
代码
#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;
}