题目链接:点击打开链接
最小圆覆盖问题,这个问题我看了好一整子……
一组点的最小覆盖圆,应该有其中的两个点或者三个点在圆的边界上,其实两个点的情况就是两个点的连线是圆的直径。
如果是两个点的情况,那么圆心就是两点连线的中点。
如果是三个点的情况,那么圆心就是三个点所构成的三角形的外心,外心是三条边中垂线的交点。
具体的求法:
假设三个点(x1,y1),(x2,y2),(x3,y3)
<pre name="code" class="cpp">#include <stdio.h>
#include <math.h>
#include <algorithm>
#define eps 1e-8
using namespace std;
struct point
{
double x, y;
}p[510];
point o;
double r;
double dis(point a, point b)
{
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
void getcircle(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;
o.x = a.x + (c1 * b2 - c2 * b1) / d;
o.y = a.y + (a1 * c2 - a2 * c1) / d;
}
int main (void)
{
int n;
while(scanf("%d", &n))
{
if(n == 0)
break;
for(int i = 0; i < n; i++)
scanf("%lf %lf", &p[i].x, &p[i].y);
r = 0.0;//半径
o = p[0];//圆心
for(int i = 1; i < n; i++)
{
if(dis(p[i], o) > r + eps)
{//先确定第一个点
r = 0.0;
o = p[i];
for(int j = 0; j < i; j++)
{//确定第二个点
if(dis(p[j], o) > r + eps)
{
o.x = (p[j].x + p[i].x) / 2.0;
o.y = (p[j].y + p[i].y) / 2.0;
r = dis(p[j], o);
for(int k = 0; k < j; k++)
{//如果还有点不在园内,那么就是三个点的情况,确定第三个点
if(dis(p[k], o) > r + eps)
{
getcircle(p[i], p[j], p[k]);
r = dis(p[k], o);
}
}
}
}
}
}
printf("%.2lf %.2lf %.2lf\n", o.x, o.y, r);
}
return 0;
}