题意:给出n(n<=1e5)个点,求一个最小的圆,与x轴相切,并且包含这n个点
思路:我第一想到的是,这个圆一定会经过一个点,再根据与x轴相切,我们可以找到最小的圆,让它包含其余的点,但是如何判断一个圆是否包含其他点花费的时间很多,这样时间复杂度肯定过不去,正解是,用二分枚举圆的半径R,那么圆心就是(X,R),然后根据每个点可以找到允许的X区间,看看是否n个区间有公共点。我最初担心的是精度问题,然而这题精度影响并不大,我的细节没处理好,比如如果y全是负的那么把他们转化为正的,还有公式列错了,这些都是粗心导致的
代码:
#include <cstdio> #include <iostream> #include <cstring> #include <ctime> #include <cstdlib> #include <vector> #include <stack> #include <algorithm> #include <map> #include <cmath> #include <queue> using namespace std; #define ll long long const int maxn=1e5+10; long long x[maxn],y[maxn],n; bool check(long double r) { for(int i=1;i<=n;i++) if(2*r*y[i]-y[i]*y[i]<0)return false; long double s=x[1]-sqrt(2*y[1]*r-y[1]*y[1]); long double t=x[1]+sqrt(2*r*y[1]-y[1]*y[1]); for(int i=1;i<=n;i++) { s=max(s,x[i]-sqrt(2*r*y[i]-y[i]*y[i])); t=min(t,x[i]+sqrt(2*r*y[i]-y[i]*y[i])); // cout<<s<<" "<<t<<endl; } if(s>t)return false; else return true; } int main() { cin>>n; for(int i=1;i<=n;i++) cin>>x[i]>>y[i]; int fla; if(y[1]>0)fla=1; else fla=-1; for(int i=1;i<=n;i++) { if(y[i]/abs(y[i])!=fla) { cout<<-1<<endl; return 0; } y[i]=abs(y[i]); } //cout<<check(1e16/2.0)<<endl; long double st=0,en=1e16; // cout<<check(en/2.0)<<endl; for(int i=1; i<=100; i++) { //cout<<st<<" "<<en<<endl; long double mid=(st+en)/2.0; if(check(mid))en=mid; else st=mid; } printf("%Lf ",st); return 0; }