链接:https://ac.nowcoder.com/acm/contest/3006/B
来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
Special Judge, 64bit IO Format: %lld

题目描述

由于牛牛战队经常要外出比赛,因此在全国各地建立了很多训练基地,每一个基地都有一个坐标(x,y)(x,y)(x,y)。

这周末,牛牛队又要出去比赛了,各个比赛的赛点都在xxx轴上。牛牛战队为了方便比赛,想找一个到达训练基地最大距离最小的地方作为比赛地。

这个问题对于牛牛战队太简单了,它就交给了你,你来帮他算一下~

输入描述:

 

输入数据第一行包含一个整数N(1≤N≤100 000)N(1 \leq N \leq 100\,000)N(1≤N≤100000),表示牛牛战队训练基地的数量。

接下来NNN行,每行包括222个整数x,y(−10 000≤x,y≤10 000)x,y(-10\,000 \leq x,y \leq 10\,000)x,y(−10000≤x,y≤10000),表示每一个训练基地的坐标。

输出描述:

 

输出一个小数,表示选择的比赛地距离各训练基地最大距离的最小值。

如果你的答案是aaa,标准答案是bbb,当∣a−b∣max(1,∣b∣)≤10−4\frac{|a-b|}{max(1,|b|)}\leq 10^{-4}max(1,∣b∣)∣a−b∣​≤10−4时,你的答案将被判定为正确。

示例1

输入

 

3
0 0
2 0
0 2

输出

 

2

说明

当在(0,0)(0,0)(0,0)比赛时,到三个训练基地的最大距离是222。可以证明这是最小值。

 

题意:

给出n个整数点,在x轴上求一点使得该点与已知n个点的最远距离最小

思路:

方法一:经分析最远距离为单峰函数,三分x坐标。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
const double eps = 1e-8;
int n;

struct node
{
    int x, y;
}s[N];

double solve(double x0)
{
    double maxx = 0;
    for(int i = 1; i <= n; ++i)
    {
        maxx = max(maxx, 1.0 * sqrt((s[i].x - x0) * (s[i].x - x0) + s[i].y * s[i].y));
    }
    return maxx;
}

int main()
{
    while(~scanf("%d", &n))
    {
        for(int i = 1; i <= n; ++i)
        {
            scanf("%d%d", &s[i].x, &s[i].y);
        }
        double l = -10000.0, r = 10000.0;
        while(r - l > eps)
        {
            double m1 = l + (r - l) / 3.0;
            double m2 = r - (r - l) / 3.0;
            if(solve(m1) > solve(m2))
                l = m1;
            else
                r = m2;
        }
        printf("%.4f\n", solve(l));
    }
    return 0;
}

方法二:将n个点以x轴对称一遍,就成了最小圆覆盖裸题。

#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
const int N = 2e5 + 5;

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

node c; ///圆心
double r;   ///半径

int sgn(double x)
{
    if (fabs(x) < eps)
        return 0;
    else
        return x < 0 ? -1 : 1;
}

double Distance(node A, node B) ///两点距离
{
    return hypot(A.x - B.x, A.y - B.y); ///hypot(a, b)求以a, b为直角边的直角三角形斜边长
}

///求三角形abc的外接圆圆心
node circle_center(const node a, const node b, const node c)
{
    node center;
    double a1 = b.x - a.x, b1 = b.y - a.y, c1 = (a1 * a1 + b1 * b1) / 2;
    double a2 = c.x - a.x, b2 = c.y - a.y, c2 = (a2 * a2 + b2 * b2) / 2;
    double d = a1 * b2 - a2 * b1;
    center.x = a.x + (c1 * b2 - c2 * b1) / d;
    center.y = a.y + (a1 * c2 - a2 * c1) / d;
    return center;
}

///求最小圆覆盖,返回圆心c和半径r:
void min_cover_circle(int n)
{
    random_shuffle(p, p + n);             ///打乱所有点
    c = p[0];
    r = 0;                    ///第一个点
    for (int i = 1; i < n; ++i)        ///剩下所有点
    {
        if (sgn(Distance(p[i], c) - r) > 0) ///pi在圆外部
        {
            c = p[i];
            r = 0;                ///将圆心设为pi半径为0
            for (int j = 0; j < i; ++j) ///重新检查前面的点
            {
                if (sgn(Distance(p[j], c) - r) > 0)///两点定圆
                {
                    c.x = (p[i].x + p[j].x) / 2;
                    c.y = (p[i].y + p[j].y) / 2;
                    r = Distance(p[j], c);
                    for (int k = 0; k < j; ++k)
                    {
                        if (sgn(Distance(p[k], c) - r) > 0)
                        {
                            c = circle_center(p[i], p[j], p[k]);
                            r = Distance(p[i], c);
                        }
                    }
                }
            }
        }
    }
}

int main()
{
    int n;
    while(~scanf("%d", &n))
    {
        for(int i = 0; i < n; ++i)
        {
            scanf("%lf%lf", &p[i].x, &p[i].y);
            p[i + n].y = -1.0 * p[i].y;
            p[i + n].x = p[i].x;
        }
        n *= 2;
        min_cover_circle(n);
        printf("%.4f\n",r);
    }
    return 0;
}