cf 1059d 逆向思维 二分 简单几何
题意 给定n个点 问相切于x轴的圆,将所有的点都覆盖的最小半径是多少。
思路 : 问最小半径想到二分,但是判定条件如何去寻找?
不如将那n个点作为圆心 ,以半径r做圆, 符合条件的圆心在做完的圆内, 不过由于要和x轴相切,// (x-xa)*(x-xa)+(r-ya)*(r-ya) < =r*r
所以最长的距离 并不是x[i]+r~x[i]-r 要求出极限的 d = (r*r - (r-y[a])^2) 用x[i]+- d 才是符合条件的区间
这样枚举n次 之后 看看有没有交集 就可以判定答案是否符合了 注意精度问题(将式子化简..)
#include<bits/stdc++.h> using namespace std; #define ll long long #define pb push_back #define mp make_pair #define fi first #define se second #define pii pair<int,int> #define all(v) v.begin(),v.end() /* 题意 给定n个点 问相切于x轴的圆,将所有的点都覆盖的最小半径是多少。*/ const int N = 1e5+4; const int INF =1E9+4; const ll mod =1e9+7; const double eps = 1e-8; double x[N],y[N]; int n; bool check(double R){ //(x-xa)*(x-xa)+(r-ya)*(r-ya) < =r*r double l = -1e18,r = 1e18; for(int i=1;i<=n;++i){ if(R*2<y[i])return false; // double d = sqrt ( ( R*R - (R-y[i])*(R-y[i])) ); double d = sqrt( y[i] * (2*R-y[i]) ); l = max(l,x[i]-d); r= min(r,x[i]+d); } return (l-r+eps)<=0; } int main(){ cin>>n; int f=0; for(int i=1;i<=n;++i){ scanf("%lf %lf",&x[i],&y[i]); if(y[i]>0)f++; if(y[i]<0)y[i]=-y[i]; } if(f!=n && f!=0){ printf("-1\n");return 0; } double r = 1e18;double l = 0; double mid; for(int i=1;i<=300;++i){ mid = (r+l)/2; if(check ( mid ) ){ r= mid; } else l = mid; } printf("%.10lf\n",mid); return 0; }