1. 程式人生 > 實用技巧 >習題:Nature Reserve(二分)

習題:Nature Reserve(二分)

題目

傳送門

思路

我們發現如果直接算半徑不好算

考慮二分半徑

因為圓和\(y=0\)相切

所以圓心一定在直線\(y=r\)上面

考慮每個點和圓心的距離一定小於等於\(r\)

所以針對每一個點,我們都可以求出一個區間,使得圓心和點的距離小於等於\(r\),之後求個交集就行了

這道題精度卡的有點嚴,所以要將求距離的公式化簡一下

程式碼

#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
const double eps=1e-9;
struct node
{
    double x;
    double y;
}a[100005];
int n;
int tot;
double l=0,r=1e18,mid;
double f_abs(double x)
{
    return x<0?-x:x;
}
bool check(double cnt)
{
    double lef=-100000000,rig=100000000;
    for(int i=1;i<=n;i++)
    {
        if(f_abs(a[i].y-cnt)>cnt)
            return 0;
        double L=sqrt(a[i].y*(2*cnt-a[i].y)),R;
        R=a[i].x+L;
        L=a[i].x-L;
        if(rig<L||R<lef)
            return 0;
        lef=max(lef,L);
        rig=min(rig,R);
        //printf("%.2lf %.2lf\n",lef,rig);
    }
   // cout<<endl;
    return 1;
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i].x>>a[i].y;
    for(int i=1;i<=n;i++)   
    {
        if(a[i].y>0)
            tot++;
    }
    if(!(tot==n||tot==0))
    {
        cout<<"-1";
        return 0;
    }
    for(int i=1;i<=n;i++)
        a[i].y=f_abs(a[i].y);
    for(int i=1;i<=300;i++)
    {
        mid=(l+r)/2;
        if(check(mid))
            r=mid;
        else
            l=mid;
    }
    printf("%.8lf",mid);
    return 0;
}