题目描述
给出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
随机增量法:
我们先把所有点随机化(这点很重要)。
然后从第一个点开始判断,如果该点在圆的内部,直接忽略。否则以该点为圆心,半径为0找新的圆。
然后找到第二个在圆外的点,新的圆点就是两点的中点,半径也可求出。然后找第三个在圆外的点,之后根据三点定圆。然后一直反复即可。
三点定圆,通过圆心到三点的距离即可推出。
推荐博客:三点定圆的求法
然后这样看似是 n^3的复杂度,但是其实是 O(n)的复杂度,证明比较繁琐(我也不会)。
大概就是:当点完全随机时,第i个点在前i-1个点的最小覆盖圆外的几率是3/i
(学什么,什么不考。只有多学点咯!!!)
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e5+10;
int n;
double r;
struct node{double x,y;}t[N],res;
inline double dis(node a,node b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
inline int in_circle(node a){return dis(a,res)<=r?1:0;}
inline void get_circle(node p1,node p2,node p3){
double a=p1.x-p2.x,b=p1.y-p2.y,c=p1.x-p3.x,d=p1.y-p3.y;
double e=((p1.x*p1.x-p2.x*p2.x)-(p2.y*p2.y-p1.y*p1.y))/2;
double f=((p1.x*p1.x-p3.x*p3.x)-(p3.y*p3.y-p1.y*p1.y))/2;
res.x=(b*f-d*e)/(b*c-a*d),res.y=(c*e-a*f)/(b*c-a*d);
r=dis(res,p1);
}
void solve(){
random_shuffle(t+1,t+1+n);
for(int i=1;i<=n;i++){
if(!in_circle(t[i])){
res=t[i],r=0;
for(int j=1;j<i;j++){
if(!in_circle(t[j])){
res.x=(t[i].x+t[j].x)/2,res.y=(t[i].y+t[j].y)/2;
r=dis(t[i],res);
for(int k=1;k<j;k++){
if(!in_circle(t[k])){
get_circle(t[i],t[j],t[k]);
}
}
}
}
}
}
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++) scanf("%lf %lf",&t[i].x,&t[i].y);
solve();
printf("%.10lf\n",r);
printf("%.10lf %.10lf\n",res.x,res.y);
return 0;
}