2020牛客寒假算法基础集训营5 B 牛牛战队的比赛地 【三分求最值】

题目描述

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

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

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

输入描述

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

接下来N行,每行包括2个整数x,y(−10 000≤x,y≤10 000),表示每一个训练基地的坐标。

输出描述

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

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

示例输入

3
0 0
2 0
0 2 

示例输出 

2

分析:

对于x轴上任意一个点,距离n个点的最大值为 \small \max_i(x-x_i)^2+y_i^2,这里用距离的平方代替距离,效果相同。

可以看到,这是在多个二次函数的值中取最大值。

这类函数有如下性质:

1. 如果一个函数是若干个下凸函数的最大值,这个函数只能先减后增,那么这个函数就也是一个下凸函数;
2. 如果一个函数是若干个上凸函数的最小值,这个函数只能先增后减,那么这个函数就也是一个上凸函数。

所以上述函数就是一个下凸函数。

所以就转化为求一个下凸函数的最小值,可以将区间不断三分求得。

具体解释见代码。

#include<iostream>
#include<cmath>
using namespace std;
struct coord
{
	double x,y;
}A[100005];
double ans,l,r,mid,X;
int n;
const double eps = 1e-6;//精度设置

double check(double x){ //求出当前的点到N个点的最大值,即max函数对应点的值
	double tmax=0;
	for(int i = 0;i < n;++i){
		double dis = sqrt((A[i].x-x)*(A[i].x-x)+A[i].y*A[i].y);
		tmax=max(tmax,dis);
	}
    return tmax;
}

double tsearch(double left,double right){
    int i;
    double mid,midmid;
    for(i=0;i<100;i++){     //循环100次,其实可以小一点,满足精度要求即可
        mid=left+(right-left)/2;    //区间中点
        midmid=mid+(right-mid)/2;   //左半区间中点
        if(check(mid)>check(midmid)) //极大值求法
            left=mid;
        else
            right=midmid;
    }
    return mid;
}


int main(){
	scanf("%d",&n);
    l = 10005;
    r = -10005;
    int x,y;
    for(int i = 0;i < n;++i)
    {
        scanf("%d%d",&x,&y);
        A[i].x=x;
        A[i].y=y;
        if(A[i].x < l)	l = A[i].x;
        if(A[i].x > r)	r = A[i].x;//寻找左右边界l,r
    }
    ans=tsearch(l,r);
    printf("%.9lf\n",check(ans));
	return 0;
}
发布了30 篇原创文章 · 获赞 5 · 访问量 900

猜你喜欢

转载自blog.csdn.net/qq_42840665/article/details/104320190
今日推荐