Description
有 \(N\) 个点,求与 \(y=0\) 相切的,包含这 \(N\) 个点的最小圆的半径。
Solution
考虑二分半径,现在要检验 \(r\) 是否可行,显然对于每个 \((x_i,y_i)\) 我们可以计算出 \(d=\sqrt {r^2 - (y_i-r)^2}\),则区间 \([x_i-d, x_i+d]\) 是可行的,我们只需要验证所有区间是否有交即可。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 100005;
struct point
{
double x,y;
} p[N];
int n;
bool check(double r)
{
double mn=1e38,mx=-1e38;
for(int i=1;i<=n;i++)
{
if(r*r-(p[i].y-r)*(p[i].y-r)<-1e-9) return false;
double d=sqrt(r*r-(p[i].y-r)*(p[i].y-r));
mn=min(mn,p[i].x+d);
mx=max(mx,p[i].x-d);
}
return mn-mx>=-1e-9;
}
signed main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>p[i].x>>p[i].y;
double mx=0;
for(int i=1;i<=n;i++) mx=max(mx,max(abs(p[i].x),abs(p[i].y)));
double ymn=1e18,ymx=-1e18;
for(int i=1;i<=n;i++) ymn=min(ymn,p[i].y), ymx=max(ymx,p[i].y);
if(ymn<0 && ymx>0)
{
cout<<-1<<endl;
return 0;
}
for(int i=1;i<=n;i++) p[i].y=abs(p[i].y);
double l=0,r=mx*mx*10;
while(r-l>1e-8 && (r-l)/r>1e-10)
{
double mid=(l+r)/2;
// cout<<"mid="<<mid<<endl;
if(check(mid)) r=mid;
else l=mid;
}
if(r>mx*mx*5)
{
cout<<-1<<endl;
}
else
{
printf("%.10lf\n",r);
}
}