给出平面上N个点,请求出一个半径最小的圆覆盖住所有的点
洛谷P1742 最小圆覆盖
洛谷P2533 [AHOI2012]信号塔
显然易证最优解的圆一定是以某两个点连线为直径的圆 或 某三个点组成的三角形的外接圆
初始将圆心定为第一个点,R=0
1.枚举第一个点 i,若点 i 不在目前圆内,设它为圆心,进入2
2.再枚举第二个点 j,若点 j 不在当前圆内,设当前圆为以 i,j 为直径的圆,进入3
3.枚举第三个点 k,若点 k 不在当前圆内,设当前圆为 i,j,k 的外接圆
看似 O ( n 3 ) O(n^3) O(n3)的复杂度,但点集随机打乱后期望复杂度 O ( n ) O(n) O(n),蒟蒻不会证
关于三点定圆
设三个点为 ( x 1 , y 1 ) , ( x 2 , y 2 ) , ( x 3 , y 3 ) (x_1,y_1),(x_2,y_2),(x_3,y_3) (x1,y1),(x2,y2),(x3,y3),圆心为 ( x 0 , y 0 ) (x_0,y_0) (x0,y0)
带入圆的标准方程
{ ( x 1 − x 0 ) 2 + ( y 1 − y 0 ) 2 = r 2 ( x 2 − x 0 ) 2 + ( y 2 − y 0 ) 2 = r 2 ( x 3 − x 0 ) 2 + ( y 3 − y 0 ) 2 = r 2 \left\{\begin{aligned} (x_1-x_0)^2+(y_1-y_0)^2=r^2 \\(x_2-x_0)^2+(y_2-y_0)^2=r^2\\ (x_3-x_0)^2+(y_3-y_0)^2=r^2 \end{aligned}\right. ⎩⎪⎨⎪⎧(x1−x0)2+(y1−y0)2=r2(x2−x0)2+(y2−y0)2=r2(x3−x0)2+(y3−y0)2=r2
②-①,③-②之后化简
{ ( x 2 − x 1 ) x 0 + ( y 2 − y 1 ) y 0 = ( x 2 2 − x 1 2 ) − ( y 1 2 − y 2 2 ) 2 ( x 3 − x 2 ) x 0 + ( y 3 − y 2 ) y 0 = ( x 3 2 − x 2 2 ) − ( y 2 2 − y 3 2 ) 2 \left\{\begin{aligned} (x_2-x_1)x_0+(y_2-y_1)y_0=\frac{(x_2^2-x_1^2)-(y_1^2-y_2^2)}{2} \\(x_3-x_2)x_0+(y_3-y_2)y_0=\frac{(x_3^2-x_2^2)-(y_2^2-y_3^2)}{2} \end{aligned}\right. ⎩⎪⎪⎨⎪⎪⎧(x2−x1)x0+(y2−y1)y0=2(x22−x12)−(y12−y22)(x3−x2)x0+(y3−y2)y0=2(x32−x22)−(y22−y32)
解二元一次方程即可
a = x 2 − x 1 , b = y 2 − y 1 , c = x 3 − x 2 , d = y 3 − y 2 , e = ( x 2 2 − x 1 2 ) − ( y 1 2 − y 2 2 ) , f = ( x 3 2 − x 2 2 ) − ( y 2 2 − y 3 2 ) a=x_2-x_1,b=y_2-y_1,c=x_3-x_2,d=y_3-y_2,e=(x_2^2-x_1^2)-(y_1^2-y_2^2),f=(x_3^2-x_2^2)-(y_2^2-y_3^2) a=x2−x1,b=y2−y1,c=x3−x2,d=y3−y2,e=(x22−x12)−(y12−y22),f=(x32−x22)−(y22−y32)
x 0 = ( f ∗ b − e ∗ d ) / ( c ∗ b − a ∗ d ) / 2.0 , y 0 = ( a ∗ f − e ∗ c ) / ( a ∗ d − b ∗ c ) / 2.0 x_0=(f*b-e*d)/(c*b-a*d)/2.0,y_0=(a*f-e*c)/(a*d-b*c)/2.0 x0=(f∗b−e∗d)/(c∗b−a∗d)/2.0,y0=(a∗f−e∗c)/(a∗d−b∗c)/2.0
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long lt;
typedef double dd;
#define eps 1e-6
#define sqr(x) ((x)*(x))
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const int maxn=1000010;
int n;
struct point{dd x,y;}p[maxn],O;
dd R;
dd getd(point a,point b){ return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}
point getO(point p1,point p2,point p3)
{
point res;
dd a=p2.x-p1.x,b=p2.y-p1.y,c=p3.x-p2.x,d=p3.y-p2.y;
dd e=sqr(p2.x)+sqr(p2.y)-sqr(p1.x)-sqr(p1.y);
dd f=sqr(p3.x)+sqr(p3.y)-sqr(p2.x)-sqr(p2.y);
res.x=(f*b-e*d)/(c*b-a*d)/2.0;
res.y=(a*f-e*c)/(a*d-b*c)/2.0;
return res;
}
void mincir()
{
O=p[1]; R=0;
for(int i=1;i<=n;++i)
if(getd(p[i],O)-R>eps)
{
O=p[i]; R=0;
for(int j=1;j<i;j++)
if(getd(p[j],O)-R>eps)
{
O=(point){(p[i].x+p[j].x)/2.0,(p[i].y+p[j].y)/2.0};
R=getd(p[i],p[j])/2.0;
for(int k=1;k<j;++k)
if(getd(p[k],O)-R>eps)
{
O=getO(p[i],p[j],p[k]);
R=getd(p[i],O);
}
}
}
}
int main()
{
n=read();
for(int i=1;i<=n;++i)
scanf("%lf%lf",&p[i].x,&p[i].y);
random_shuffle(p+1,p+1+n);
mincir();
printf("%.2lf %.2lf %.2lf",O.x,O.y,R);
return 0;
}