题目描述
给出N个点,让你画一个最小的包含所有点的圆。
输入输出格式
输入格式:
先给出点的个数N,2<=N<=100000,再给出坐标Xi,Yi.(-10000.0<=xi,yi<=10000.0)
输出格式:
输出圆的半径,及圆心的坐标,保留10位小数
输入输出样例
输入样例#1: 复制
6 8.0 9.0 4.0 7.5 1.0 2.0 5.1 8.7 9.0 2.0 4.5 1.0
输出样例#1: 复制
5.0000000000 5.0000000000 5.0000000000
说明
5.00 5.00 5.0
模拟,就是三点确定一个圆,然后判断剩下的点是不是在圆内,不是的话找三个圆外的点,构成一个新的圆,这个新的圆一定会比原来的圆大,注意找的时候不是一下找三个点,因为我们要求的是最小的圆,找到第一个点的时候,直接把原来的圆的半径扩大到这个点,第二个也是,但是第三个需要特判一下,因为如果直接把半径扩大到第三个点的话,就有可能直接把上面两个点直接包含了,而我们要求的是最小的圆,所以最后一次找到这个三个点时,直接三点定圆,就一定会包含所有的点
#include<bits/stdc++.h>
using namespace std;
struct circle {double x,y,r;};
struct point {double x,y;};
point poi[100005];
int n;
double dis(point a,point b)//计算两点之间的距离函数
{
return sqrt( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) );
}
circle turn(point a,point b,point c)//三点确定一个圆
{
circle cl;
double A,B,C,D,E,F,x0,y0,r0;
A=b.x-a.x; B=b.y-a.y;
C=c.x-a.x; D=c.y-a.y;
E=( (b.x*b.x-a.x*a.x) + (b.y*b.y-a.y*a.y) )/2;
F=( (c.x*c.x-a.x*a.x) + (c.y*c.y-a.y*a.y) )/2;
x0=-(D*E-B*F)/(B*C-A*D);
y0=-(A*F-C*E)/(B*C-A*D);
r0=sqrt( (a.x-x0)*(a.x-x0) + (a.y-y0)*(a.y-y0) );
cl.x=x0; cl.y=y0; cl.r=r0;
return cl;
}
point midpoint(point a,point b)//计算中点
{
point t={.x=(a.x+b.x)/2,.y=(a.y+b.y)/2};
return t;
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
cin>>poi[i].x>>poi[i].y;
random_shuffle(poi,poi+n);//随机化
circle ans;
point temp=poi[0];
double R=0.0;
for(int i=1;i<n;i++)
if(dis(temp,poi[i])>R)
{
temp=midpoint(poi[0],poi[i]);
R=dis(poi[i],temp);
for(int j=1;j<i;j++)
if(dis(temp,poi[j])>R)
{
temp=midpoint(poi[j],poi[i]);
R=dis(poi[i],temp);
for(int k=0;k<j;k++)
if(dis(temp,poi[k])>R)
{
ans=turn(poi[i],poi[j],poi[k]);
temp=(point){.x=ans.x, .y=ans.y};
R=dis(poi[i],temp);
}
}
}
printf("%.10lf\n%.10lf %.10lf\n",R,temp.x,temp.y);
return 0;
}