Problem
Solution
其实就是个板子题……用是随机增量法,期望时间复杂度 O(n) O ( n ) 。
每次的操作就是维护一个覆盖前i个点的最小圆。
第i个点不在当前圆内,就以这个点作为圆心,重新扫前面的点
如果j不在圆内,就以这两个点的线段为直径作圆,然后再判断之前的点是否在圆内
如果k不在圆内,就构造过三点的圆,嗯……方法很暴力,直接解析几何。由于三点确定一个圆,所以枚举到第三层就够了。
过三点的圆还有个叉积的奇妙做法,可以戳一下这位dalao的讲解
注意要random_shuffle一下使得数据随机,不然从过程中就可以看出最坏复杂度可能达到
O(n3)
O
(
n
3
)
。还有特判掉没有斜率的中垂线和平行的中垂线,感觉可能会有什么情况没有考虑到,但是我也不知道,比较难卡吧,毕竟有random_shuffle。
Code
#include <algorithm>
#include <cstdio>
#include <cmath>
#define rg register
using namespace std;
typedef long long ll;
const int maxn=100010;
const double eps=1e-8;
template <typename Tp> inline void getmin(Tp &x,Tp y){if(y<x) x=y;}
template <typename Tp> inline void getmax(Tp &x,Tp y){if(y>x) x=y;}
template <typename Tp> inline void read(Tp &x)
{
x=0;int f=0;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
if(f) x=-x;
}
struct vec{
double x,y;
double dis(const vec &t){return sqrt((x-t.x)*(x-t.x)+(y-t.y)*(y-t.y));}
}o,a[maxn];
struct line{
double k,b;
}l1,l2;
int n;
double r=0;
double fabs(double x){return x>0?x:-x;}
int incircle(vec t)
{
return t.dis(o)<=r+eps;
}
vec intersection(line a,line b)
{
double x=(b.b-a.b)/(a.k-b.k);
double y=a.k*x+a.b;
return (vec){x,y};
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
read(n);
for(rg int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
random_shuffle(a+1,a+n+1);
for(rg int i=1;i<=n;i++)
if(!incircle(a[i]))
{
o=a[i];r=0;
for(rg int j=1;j<i;j++)
if(!incircle(a[j]))
{
o.x=(a[i].x+a[j].x)/2;
o.y=(a[i].y+a[j].y)/2;
r=o.dis(a[i]);
for(rg int k=1;k<j;k++)
if(!incircle(a[k]))
{
if(fabs(a[j].y-a[i].y)<=eps||fabs(a[k].y-a[i].y)<=eps) continue;
l1.k=-(a[j].x-a[i].x)/(a[j].y-a[i].y);
l1.b=(a[i].y+a[j].y)/2-l1.k*(a[i].x+a[j].x)/2;
l2.k=-(a[k].x-a[i].x)/(a[k].y-a[i].y);
l2.b=(a[i].y+a[k].y)/2-l2.k*(a[i].x+a[k].x)/2;
if(fabs(l1.k-l2.k)<=eps) continue;
o=intersection(l1,l2);r=o.dis(a[i]);
}
}
}
printf("%.10lf\n%.10lf %.10lf\n",r,o.x,o.y);
return 0;
}