bzoj2823: [AHOI2012]信号塔

6 篇文章 0 订阅
3 篇文章 0 订阅

正在计算几何入门中。。。。。。

这道题就是求最小圆覆盖。题目讲了这么多,只有6个字

对于1个点,它的最小覆盖圆是一个点。对于2个点,它们的最小覆盖圆是以它们为直径的圆。

首先考虑已知i个点被最小的圆O覆盖,若第i+1个点在圆O内,显然这i+1个点的最小覆盖圆也是O。若第i+1个点不在圆O内,设圆O1是i+1个点的最小覆盖圆。可以证明这个点在圆O1上。

然后对于点i+1,不断加入1~i的点,同样的方法可以求得另一个在圆O1上的点j。

最后固定这两个点,再不断加入1~i的点,可以得到圆O1上的3个点,于是就可以得到圆O1。

注意:圆上可以只有2个点,如钝角三角形的三个顶点。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#define Hz 1e-6
using namespace std;
struct dot{double x,y;}a[1000005],O;
int n;double R;
double sqr(double x)
{
	return x*x;
}
double dis(dot a,dot b)//求距离
{
	return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
}
dot getO(dot a,dot b)//已知2点求圆心
{
	dot k;
	k.x=(a.x+b.x)/2;
	k.y=(a.y+b.y)/2;
	return k;
}
dot getO(dot a,dot b,dot c)//已知3点求圆心
{
	double x1=-2*(a.x-b.x);
	double y1=-2*(a.y-b.y);
	double z1=a.x*a.x+a.y*a.y-b.x*b.x-b.y*b.y;
	double x2=-2*(b.x-c.x);
	double y2=-2*(b.y-c.y);
	double z2=b.x*b.x+b.y*b.y-c.x*c.x-c.y*c.y;
	dot k;
	k.x=(y1*z2-z1*y2)/(x1*y2-x2*y1);
	k.y=(x1*z2-z1*x2)/(y1*x2-y2*x1);
	return k;
}
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		scanf("%lf%lf",&a[i].x,&a[i].y);//输入时可进行随机处理,本题数据未特殊处理
	O=a[1];R=0;
	for (int i=1;i<=n;i++)
	{
		if (dis(O,a[i])<=R+Hz) continue;
		O=getO(a[1],a[i]);R=dis(O,a[i]);
		for (int j=1;j<i;j++)
		{
			if (dis(O,a[j])<=R+Hz) continue;
			O=getO(a[i],a[j]);R=dis(O,a[i]);
			for (int k=1;k<j;k++)
			{
				if (dis(O,a[k])<=R+Hz) continue;
				O=getO(a[i],a[j],a[k]);R=dis(O,a[i]);
			}
		}
	}
	printf("%.2f %.2f %.2f\n",O.x,O.y,R);
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值