天天看點

[CodeForces]1059D Nature Reserve

大意:給你一個平面上N(N<=100000)個點,問相切于x軸的圓,将所有的點都覆寫的最小半徑是多少。

計算幾何???Div2的D題就考計算幾何???某人昨天上課才和我們說這種計算幾何題看見就溜。。。。

打完比賽才發現好像并不用計算幾何,實則是一個二分答案的水題。。

發現如果點在x軸兩側就肯定不行,是以我們把所有的點都挪到一側。

我們二分一個半徑,然後發現因為圓相切于x軸,那麼這個圓的圓心一定在y=r的直線上移動。

對于所有的點,它可以被如圖的線段AC上的點覆寫,點在AC下方也同理。(終于有個圖是我自己畫的了。。。)

[CodeForces]1059D Nature Reserve

然後發現圓心的取值就在xi±√(R2-(R-yi)2)之間。

是以說把每個點的可取圓心的點的集合的交算出來,看看是不是空集,不是空集就可行。

[CodeForces]1059D Nature Reserve
[CodeForces]1059D Nature Reserve

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
using namespace std;
const double eps=1e-8;
int n;
struct Node {int x,y;}node[100005];
bool flag;
bool ck(double mid) {
    double l=-1e18,r=1e18;
    for(int i=1;i<=n;i++) {
        if(node[i].y>mid+mid) return 0;
        double range=sqrt(node[i].y*(2*mid-node[i].y));
        l=max(l,node[i].x-range);r=min(r,node[i].x+range);
    }
    return (l-r+eps)<=0;
}
int main() {
    scanf("%d",&n);
    scanf("%d%d",&node[1].x,&node[1].y);
    if(node[1].y<0) flag=1;node[1].y=abs(node[1].y);
    for(int i=2;i<=n;i++) {
        scanf("%d%d",&node[i].x,&node[i].y);
        if(flag&&node[i].y>0){puts("-1") ;return 0;}
        if(flag==false && node[i].y<0) {puts("-1");return 0;}
        node[i].y=abs(node[i].y);
    }
    double l=0,r=1e18;int cnt=300;
    while(cnt--) {
        double mid=(l+r)/2;
        if(ck(mid)) r=mid;
        else l=mid;
    }
    printf("%lf",l);
}      

Nature Reserve

我是鹹魚。轉載部落格請征得部落客同意Orz