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
");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
",mid);
    return 0;
}
原文地址:https://www.cnblogs.com/wjhstudy/p/9760668.html