#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N=2e5+5;
int n;
int x[N];
vector <double>res;
bool check(double r){
res.clear();
double cx=-1;
for(int i=1;i<=n;i++){
if(x[i]>cx){
if(res.size()==3){
return false;
}
cx=x[i]+2*r;
res.push_back(x[i]+r);
}
}
while(res.size()<3){
res.push_back(0);
}
return true;
}
int main(void){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&x[i]);
}
sort(x+1,x+1+n);
double l=0,r=5e8;
while(r-l>1e-6){
double mid=(l+r)/2;
if(check(mid)){
r=mid;
}else{
l=mid;
}
}
check(r);
printf("%lf\n",r);
for(auto p:res){
printf("%lf ",p);
}
return 0;
}
函数 check(double r)
:
这个函数的目的是检查给定的半径r
是否足够覆盖所有的点。如果当前的圆心位置cx
和下一个点的距离大于2*r
,则将下一个点的坐标添加到结果向量中。如果结果向量的大小达到3,则返回false,因为这意味着我们需要一个更大的圆来覆盖所有的点。在函数最后,如果结果向量的大小小于3,则用0填充它。这表示我们需要一个更小的圆来覆盖所有的点。
主函数
读取点的数量n
和每个点的x坐标。
对x坐标进行排序。
使用二分查找法来找到最小的半径。初始的半径范围是[0, 5e8]
,并通过不断二分这个范围来逼近最小的半径。每次检查圆心是否能覆盖所有的点,如果可以,则缩小搜索范围为[l, mid]
,否则缩小范围为[mid, r]
。
一旦找到最小的半径,再次调用check(r)
来获取覆盖所有点的圆的三个点的坐标。
输出最小的半径和三个点的坐标。
需要注意的是,这个代码只考虑了x坐标,而没有考虑y坐标。因此,它适用于所有点在一条直线上的情况。如果点不在一条直线上,这个代码就不能正确地找到一个最小的圆来覆盖所有的点。