CF1059D题解

· · 题解

题面

求一个能覆盖所有点的与 y 轴相切的最小的圆。

对于所有的点,如果它们同时出现在 y 轴的上下,输出 -1。

然后,我们二分枚举圆的半径。

如果半径为 r,

$DJ=JE=\sqrt{r\times r-X_A\times X_A}$。 我们只需枚举每一个点在半径为 $r$ 时的 $D,E$ 坐标,到最后如果还满足 $\max\limits_{i=1}^nX_D\le \min\limits_{i=1}^nX_E$ 就说明半径为 $r$ 是成立的。 代码: ```cpp #include<bits/stdc++.h> #define db long double using namespace std; int n; struct node{ int x,y; }a[100005];//储存点的坐标 bool ch(db x){ db maxl=-1e15,minr=1e15;//初始化左右端点 for(int i=1;i<=n;i++){ db c,d; if(x*x<(a[i].y-x)*(a[i].y-x))return 0;//无法与y轴相切 c=a[i].x-sqrt(x*x-(a[i].y-x)*(a[i].y-x)); d=a[i].x+sqrt(x*x-(a[i].y-x)*(a[i].y-x)); maxl=max(maxl,c); minr=min(minr,d);//更新 } return maxl<=minr; } int main() { scanf("%d",&n); bool f1,f2; f1=f2=0; for(int i=1;i<=n;i++){ scanf("%d%d",&a[i].x,&a[i].y); if(a[i].y>0)f1=1; if(a[i].y<0)f2=1; a[i].y=abs(a[i].y);//取绝对值方便处理 } if(f1&&f2){//y轴上下都有点 printf("-1"); return 0; } int T=1000;//防止死循环(血与泪的教训) db l=0,r=1e14+10,mid; while(T--){ mid=(l+r)/2; if(ch(mid))r=mid; else l=mid;//二分 } printf("%.6Lf",r); return 0; } ```