题目描述
由于牛牛战队经常要外出比赛,因此在全国各地建立了很多训练基地,每一个基地都有一个坐标(x,y)。
这周末,牛牛队又要出去比赛了,各个比赛的赛点都在x轴上。牛牛战队为了方便比赛,想找一个到达训练基地最大距离最小的地方作为比赛地。
这个问题对于牛牛战队太简单了,它就交给了你,你来帮他算一下~
输入描述
输入数据第一行包含一个整数N(1≤N≤100 000),表示牛牛战队训练基地的数量。
接下来N行,每行包括2个整数x,y(−10 000≤x,y≤10 000),表示每一个训练基地的坐标。
输出描述
输出一个小数,表示选择的比赛地距离各训练基地最大距离的最小值。
如果你的答案是a,标准答案是b,当 时,你的答案将被判定为正确。
示例输入
3
0 0
2 0
0 2
示例输出
2
分析:
对于x轴上任意一个点,距离n个点的最大值为 ,这里用距离的平方代替距离,效果相同。
可以看到,这是在多个二次函数的值中取最大值。
这类函数有如下性质:
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;
}