Buried memory(hdu 3007)

题目链接:点击打开链接

最小圆覆盖问题,这个问题我看了好一整子……

一组点的最小覆盖圆,应该有其中的两个点或者三个点在圆的边界上,其实两个点的情况就是两个点的连线是圆的直径。

如果是两个点的情况,那么圆心就是两点连线的中点。

如果是三个点的情况,那么圆心就是三个点所构成的三角形的外心,外心是三条边中垂线的交点。

具体的求法:

假设三个点(x1,y1),(x2,y2),(x3,y3)

    设过(x1,y1),(x2,y2)的直线l1方程为Ax+By=C,它的中点为(midx,midy)=((x1+x2)/2,(y1+y2)/2),l1中垂线方程为A1x+B1y=C1;则它的中垂线方程中A1=-B=x2-x1,B1=A=y2-y1,C1=-B*midx+A*midy=((x2^2-x1^2)+(y2^2-y1^2))/2;

    同理可以知道过(x1,y1),(x3,y3)的直线的中垂线的方程。

    于是这两条中垂线的交点就是圆心。

    设两条直线为A1x+B1y=C1和A2x+B2y=C2。

    设一个变量det=A1*B2-A2*B1;

    如果det=0,说明两直线平行;若不等于0,则求交点:x=(B2*C1 -B1*C2)/det,y=(A1*C2-A2*C1)/det;

#include 
#include 
#include 
#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;
} 


你可能感兴趣的:(HDU,计算几何)