http://www.lydsy.com/JudgeOnline/problem.php?id=2823 (题目链接)
题意:求最小圆覆盖
Solution
关于最小圆覆盖的做法,论文里面都有。其实真正麻烦的是求三角形的外心。
给定a(x1,y1) b(x2,y2) c(x3,y3)求外接圆心坐标O(x,y)。
1. 首先,外接圆的圆心是三角形三条边的垂直平分线的交点,我们根据圆心到顶点的距离相等,可以列出以下方程:
(x1-x)*(x1-x)-(y1-y)*(y1-y)=(x2-x)*(x2-x)+(y2-y)*(y2-y);
(x2-x)*(x2-x)+(y2-y)*(y2-y)=(x3-x)*(x3-x)+(y3-y)*(y3-y);
2.化简得到:
2*(x2-x1)*x+2*(y2-y1)y=x2^2+y2^2-x1^2-y1^2;
2*(x3-x2)*x+2*(y3-y2)y=x3^2+y3^2-x2^2-y2^2;
令A1=2*(x2-x1);
B1=2*(y2-y1);
C1=x2^2+y2^2-x1^2-y1^2;
A2=2*(x3-x2);
B2=2*(y3-y2);
C2=x3^2+y3^2-x2^2-y2^2;
即
A1*x+B1y=C1;
A2*x+B2y=C2;
3.最后根据克拉默法则:
x=((C1*B2)-(C2*B1))/((A1*B2)-(A2*B1));
y=((A1*C2)-(A2*C1))/((A1*B2)-(A2*B1));
因此,x,y为最终结果;
代码:
// bzoj2823
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<vector>
#define eps 1e-10
#define inf 2147483640
#define LL long long
#define free(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
using namespace std;
inline LL getint() {
LL x=0,f=1;char ch=getchar();
while (ch>'9' || ch<'0') {if (ch=='-') f=-1;ch=getchar();}
while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int maxn=1000010;
struct point {double x,y;}p[maxn];
int n;
double dis(point a,point b) {
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
point center(point a,point b,point c) {
double a1=b.x-a.x,b1=b.y-a.y,c1=(a1*a1+b1*b1)/2;
double a2=c.x-a.x,b2=c.y-a.y,c2=(a2*a2+b2*b2)/2;
double d=a1*b2-a2*b1;
return (point){a.x+(c1*b2-c2*b1)/d,a.y+(a1*c2-a2*c1)/d};
}
int main() {
scanf("%d",&n);
for (int i=1;i<=n;i++) {scanf("%lf%lf",&p[i].x,&p[i].y);swap(p[i],p[rand()%i+1]);}
point c=p[1];double r=0;
for (int i=2;i<=n;i++) {
if (dis(c,p[i])<=r+eps) continue;
c=p[i];r=0;
for (int j=1;j<i;j++) {
if (dis(c,p[j])<=r+eps) continue;
c.x=(p[i].x+p[j].x)/2;
c.y=(p[i].y+p[j].y)/2;
r=dis(c,p[j]);
for (int k=1;k<j;k++) {
if (dis(c,p[k])<=r+eps) continue;
c=center(p[i],p[j],p[k]);
r=dis(p[k],c);
}
}
}
printf("%.2f %.2f %.2f",c.x,c.y,r);
return 0;
}