double 在1e17以后就不能顾及小数,所以用一下加精度的技巧
sqrt(r*r-d*d)=sqrt(r+d)*sqrt(r-d)
遇到误差在几位以内的注意要修改二分的精度,用最大的数据去乘以精度即可
#include<bits/stdc++.h> using namespace std; const double esp = 1e-7; const double inf = 1e14; double sgn(double x){ if(fabs(x)<esp)return 0; if(x<0)return -1; return 1; } struct Point { double x,y; Point(){} Point (double x,double y):x(x),y(y){} double distance(Point p){ return hypot(x-p.x,y-p.y); } }; struct circle{ Point p; double r; circle(){} circle(Point p,double r):p(p),r(r){} int relation(Point b){ double dst=b.distance(p); if(sgn(dst-r)<0)return 2; else if(sgn(dst-r)==0)return 1; return 0; } int relationline(double y){//直线只有y=b double dst=fabs(y-p.y); if(sgn(dst-r)<0)return 2; else if(sgn(dst-r)==0)return 1; return 0; } int pointcrossline(double y,Point &p1,Point &p2){ if(!(*this).relationline(y))return 0; Point a=Point(p.x,y); double d=fabs(p.y-y); d=sqrt(r*r-d*d); if(sgn(d)==0){ p1=a,p2=a; return 1; } p1=Point(a.x-d,y); p2=Point(a.x+d,y); return 2; } }; #define maxn 100005 Point p[maxn]; int n; //判断半径r是否可行,每个点画个圆和y=r相交,维护L,R即可 int judge(long double r){ long double L=-1e15,R=1e15; for(int i=1;i<=n;i++){ if(r*2-p[i].y<0)return 0; long double d=fabs(r-p[i].y); d=sqrt(r+d)*sqrt(r-d);//这里要扩大精度 L=max(L,p[i].x-d);R=min(R,p[i].x+d); } return L<=R; } int main(){ cin>>n; int flag0=0,flag1=0; double Min=inf,Max=-inf,M=-inf; for(int i=1;i<=n;i++){ scanf("%lf%lf",&p[i].x,&p[i].y); if(p[i].y<0) flag0=1; else flag1=1; Min=min(Min,p[i].x);Max=max(Max,p[i].x); M=max(M,fabs(p[i].y)); } if(flag0 && flag1){puts("-1");return 0;} if(flag0){ for(int i=1;i<=n;i++) p[i].y *= -1; } double l=0,r=inf,mid,ans=-1,x=max((Max-Min),M)*esp; while(x<r-l){ mid=(l+r)/2; if(judge(mid)) ans=mid,r=mid; else l=mid; } printf("%.7lf",ans); }