[CF1059D] Nature Reserve - 二分,几何

Description

有 \(N\) 个点,求与 \(y=0\) 相切的,包含这 \(N\) 个点的最小圆的半径。

Solution

考虑二分半径,现在要检验 \(r\) 是否可行,显然对于每个 \((x_i,y_i)\) 我们可以计算出 \(d=\sqrt {r^2 - (y_i-r)^2}\),则区间 \([x_i-d, x_i+d]\) 是可行的,我们只需要验证所有区间是否有交即可。

#include <bits/stdc++.h>
using namespace std;

#define int long long 
const int N = 100005;

struct point 
{
    double x,y;
} p[N];

int n;

bool check(double r)
{
    double mn=1e38,mx=-1e38;
    for(int i=1;i<=n;i++)
    {
        if(r*r-(p[i].y-r)*(p[i].y-r)<-1e-9) return false;
        double d=sqrt(r*r-(p[i].y-r)*(p[i].y-r));
        mn=min(mn,p[i].x+d);
        mx=max(mx,p[i].x-d);
    }
    return mn-mx>=-1e-9;
}

signed main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>p[i].x>>p[i].y;
    double mx=0;
    for(int i=1;i<=n;i++) mx=max(mx,max(abs(p[i].x),abs(p[i].y)));
    double ymn=1e18,ymx=-1e18;
    for(int i=1;i<=n;i++) ymn=min(ymn,p[i].y), ymx=max(ymx,p[i].y);
    if(ymn<0 && ymx>0) 
    {
        cout<<-1<<endl;
        return 0;
    }
    for(int i=1;i<=n;i++) p[i].y=abs(p[i].y);
    double l=0,r=mx*mx*10;
    while(r-l>1e-8 && (r-l)/r>1e-10)
    {
        double mid=(l+r)/2;
        // cout<<"mid="<<mid<<endl;
        if(check(mid)) r=mid;
        else l=mid;
    }
    if(r>mx*mx*5)
    {
        cout<<-1<<endl;
    }
    else 
    {
        printf("%.10lf\n",r);
    }
}
上一篇:[LeetCode] 1845. Seat Reservation Manager


下一篇:【蓝桥杯】【基础】十进制转十六进制