题目链接:戳我
一个最小圆覆盖的模板题吧。。。
最小圆覆盖怎么做??
就是枚举三个点,第一个点做圆心,第二、三个点和第一个点联合起来确定一个圆。
看起来是\(O(n^3)\)的是不是?但是其实均摊时间复杂度是\(O(n)\)的。具体为什么我也不会证,但是我们可以知道,如果枚举后面的点已经在前面确定好的圆里面就不需要再计算了是吧qwqwq
对于三个点(x1,y1),(x2,y2),(x3,y3),和未知的圆心(x0,y0)
对于三个点(x1,y1),(x2,y2),(x3,y3),和未知的圆心(x0,y0)
\(\begin{cases}(x1-x0)^2+(y1-y0)^2=r^2\\(x2-x0)^2+(y2-y0)^2=r^2\\(x3-x0)^2+(y3-y0)^2=r^2\end{cases}\)
\(\begin{cases}(x2-x3)x0+(y2-y3)y0=\frac{(x2^2-x3^2)+(y2^2-y3^2)}{2}\\(x1-x2)x0+(y1-y2)y0=\frac{(x1^2-x2^2)+(y1^2-y2^2)}{2}\end{cases}\)
\(\begin{cases}a*x0+b*y0=e\\c*x0+d*y0=f\end{cases}\)
\(\begin{cases}x=\frac{de-bf}{ad-bc};\\y=\frac{ce-af}{bc-ad};\end{cases}\)
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<ctime>
#define eps 1e-15
#define MAXN 500010
using namespace std;
int n;
double r;
struct Node{double x,y;}node[MAXN],o;
inline double dist(Node a,Node b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
inline void solve(Node A,Node B,Node C)
{
double a=(B.x-C.x)*2;
double b=(B.y-C.y)*2;
double c=(A.x-B.x)*2;
double d=(A.y-B.y)*2;
double e=(B.x*B.x-C.x*C.x)+(B.y*B.y-C.y*C.y);
double f=(A.x*A.x-B.x*B.x)+(A.y*A.y-B.y*B.y);
o.x=(d*e-b*f)/(a*d-b*c);
o.y=(c*e-a*f)/(b*c-a*d);
r=dist(A,o);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lf%lf",&node[i].x,&node[i].y);
random_shuffle(&node[1],&node[n+1]);
o=node[1]; r=0;
for(int i=2;i<=n;i++)
if(dist(node[i],o)>r+eps)
{
o=node[i];r=0;
for(int j=1;j<i;j++)
{
if(dist(node[j],o)>r+eps)
{
o.x=(node[i].x+node[j].x)/2;
o.y=(node[i].y+node[j].y)/2;
r=dist(o,node[j]);
for(int k=1;k<j;k++)
if(dist(node[k],o)>r+eps)
solve(node[i],node[j],node[k]);
}
}
}
printf("%.3lf\n",r);
}