D

题意:给出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;
}

  

原文地址:https://www.cnblogs.com/carcar/p/9762453.html