题面
题意
给出n个点,输出最小覆盖圆的坐标和半径
做法
首先用random_shuffle随机化点的顺序,然后做以下操作:
1.枚举所有点(设为i从2到n),若有点在当前圆外(一开始的圆为第一个点,半径为0),则将圆心变为这个点,半径改为0,进入2.
2.枚举已经考虑过的点(设为j从1到i-1),若有点在当前圆外,将圆心变为i,j两点的中点,半径为两点距离的一半.
3.枚举j之前的的点(设为k从1到j-1),若有点在圆外,则更新为i,j,k三点的外接圆,同时更新半径.
复杂度:目测是O(n^3)的,但因为点是随机的(这很重要),所以从概率的角度上看是O(n)的.
代码(解析几何)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<algorithm>
#define db double
#define N 1000100
#define eps (1e-8)
using namespace std;
int n;
db r;
struct Node
{
db x,y;
} node[N],mid;
struct Xn
{
db k,b;
};
//计算两点之间的距离
inline db len(Node u,Node v)
{
return sqrt((u.x-v.x)*(u.x-v.x)+(u.y-v.y)*(u.y-v.y));
}
//判断点是否在圆外
inline bool out(Node u)
{
return(len(u,mid)>r+eps);
}
//求直线的解析式
inline Xn jx(Node u,Node v)
{
Xn res;
res.k=(u.y-v.y)/(u.x-v.x),res.b=u.y-res.k*u.x;
return res;
}
//算两点的中点
inline Node middle(Node u,Node v)
{
Node res;
res.x=(u.x+v.x)/2,res.y=(u.y+v.y)/2;
return res;
}
//求与该直线垂直的直线
inline Xn cz(Xn u,Node v)
{
Xn res;
res.k=-1/(u.k),res.b=v.y-v.x*res.k;
return res;
}
//求该横坐标在直线上对应的点
inline Node qd(Xn u,db v)
{
Node res;
res.x=v,res.y=u.k*v+u.b;
return res;
}
//求两直线的交点
inline Node jd(Xn u,Xn v)
{
db res;
res=(v.b-u.b)/(u.k-v.k);
return qd(u,res);
}
//求三个点的外接圆
inline Node wj(Node u,Node v,Node w)
{
Xn a,b;
a=jx(u,v),b=jx(v,w);
if(qd(a,w.x).y==w.y) //三点一线的情况下
{
Node res;
res.x=(max(u.x,max(v.x,w.x))+min(u.x,min(u.x,v.x)))/2,res.y=(min(u.x,min(v.y,w.y))+min(u.y,min(u.y,v.y)))/2;
return res;
}
a=cz(a,middle(u,v)),b=cz(b,middle(v,w));
return jd(a,b);
}
int main()
{
srand(time(0));
register int i,j,k;
cin>>n;
for(i=1; i<=n; ++i)
{
scanf("%lf%lf",&node[i].x,&node[i].y);
}
random_shuffle(node+1,node+n+1),mid=node[1],r=0;
for(i=2; i<=n; ++i)
{
if(out(node[i]))
{
mid=node[i],r=0;
for(j=1; j<i; ++j)
{
if(out(node[j]))
{
mid=middle(node[i],node[j]),r=len(mid,node[i]);
for(k=1; k<j; ++k)
{
if (out(node[k]))
mid=wj(node[i],node[j],node[k]),r=len(mid,node[i]);
}
}
}
}
}
printf("%.2lf %.2lf %.2lf",mid.x,mid.y,r);
}
代码(计算几何)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#define db double
#define eps 1e-8
#define N 1001000
using namespace std;
int n;
db r;
struct Node
{
db x,y;
void make(db u,db v){x=u,y=v;}
Node operator + (const Node &u) const{Node res;res.x=x+u.x,res.y=y+u.y;return res;}
Node operator - (const Node &u) const{Node res;res.x=x-u.x,res.y=y-u.y;return res;}
Node operator * (const db &u) const{Node res;res.x=u*x,res.y=y*u;return res;}
Node operator / (const db &u) const{Node res;res.x=x/u,res.y=y/u;return res;}
bool operator < (const Node &u){return x<u.x;}
bool operator > (const Node &u){return x>u.x;}
} node[N],ans;
struct Xn
{
Node a,v;
};
inline db lenf(Node u,Node v){return (u.x-v.x)*(u.x-v.x)+(u.y-v.y)*(u.y-v.y);}
inline db len(Node u,Node v){return sqrt(lenf(u,v));}
inline bool out(Node u){return lenf(u,ans)>r*r+eps;}
inline Node mid(Node u,Node v){return (u+v)/2.0;}
inline db cj(Node u,Node v){return u.x*v.y-u.y*v.x;}
inline Node xz(Node u){Node res;res.make(-u.y,u.x);return res;}
inline Node jd(Xn u,Xn v)
{
db t=cj(u.v,(v.a-u.a))/cj(v.v,u.v);
return v.a+v.v*t;
}
inline Node wj(Node u,Node v,Node w)
{
Xn a,b;
a.a=mid(u,v),b.a=mid(u,w);
a.v=xz(v-u),b.v=xz(w-u);
if(fabs(cj(a.v,b.v))<eps)
{
if(u>v) swap(u,v);
if(u>w) swap(u,w);
if(v>w) swap(v,w);
return mid(u,w);
}
return jd(a,b);
}
int main()
{
srand(517);
int i,j,k;
Node a,b,c;
/*
a.make(0,0),b.make(0,3),c.make(-3,-3);
a=wj(a,b,c);
cout<<a.x<<" "<<a.y;
//*/
cin>>n;
for(i=1; i<=n; i++)
{
scanf("%lf%lf",&node[i].x,&node[i].y);
}
random_shuffle(node+1,node+n+1);
ans=node[1],r=0;
for(i=2; i<=n; i++)
{
if(!out(node[i])) continue;
ans=node[i];
r=0;
for(j=1; j<i; j++)
{
if(!out(node[j])) continue;
ans=mid(node[i],node[j]);
r=len(node[i],ans);
for(k=1; k<j; k++)
{
if(!out(node[k])) continue;
ans=wj(node[i],node[j],node[k]);
r=len(node[i],ans);
}
}
}
printf("%.2f %.2f %.2f",ans.x,ans.y,r);
}