P1742 最小圆覆盖

该博客介绍了如何使用O(n^3)复杂度的算法解决找到包含所有给定点的最小圆问题。博主首先指出最优解是基于两点的直径圆或三点的外接圆,并给出了相应的数学推导。然后提供了C++代码实现,包括初始化、三点定圆的计算方法以及随机打乱点集以降低平均复杂度。最后,博主展示了完整的代码并运行结果。
摘要由CSDN通过智能技术生成

P1742 最小圆覆盖

题意:

给出N个点,让你画一个最小的包含所有点的圆。

题解:

先说结论:
最优解的圆一定是在以某两个点连线为直径的圆 或者 某三个点组成的三角形的外接圆
初始化将某个圆心定为第一个点,R=0

  1. 枚举第一个点i,如果点i不在当前圆内,设它为圆心,进入2
  2. 再枚举第二个点j,若点j不在当前圆内,设当前圆内为以i,j为直径的圆,进入3
  3. 枚举第三个点k,若点k不在当前圆内,设当前圆为i,j,k的外界圆

这样三个for循环,复杂度为O(n^3),但是点集随机打乱后期望复杂度是O(n)
如何三点定圆?
我们知道三点的坐标,直接公式推导即可
我就不推导了,直接放结论
在这里插入图片描述
比赛时现推,或者直接抄模板

代码:

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define re register
il int read()
{
    re int x = 0, f = 1; re char c = getchar();
    while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
    return x * f;
}
#define eps 1e-12
#define maxn 100005
#define ff(x) (x) * (x)
int n, m;
double r;
struct node
{
	double x, y;
}o, e[maxn];
il double dis(node a, node b){return sqrt(ff(a.x - b.x) + ff(a.y - b.y));}
il void get(node a, node b, node c)
{
	double a1 = b.x - a.x, a2 = c.x - a.x, b1 = b.y - a.y, b2 = c.y - a.y;
	double c1 = (ff(b.x) - ff(a.x) + ff(b.y) - ff(a.y));
	double c2 = (ff(c.x) - ff(a.x) + ff(c.y) - ff(a.y));
	o = (node){(b2 * c1 - b1 * c2) / (b2 * a1 * 2 - b1 * a2 * 2), 
			   (a2 * c1 - a1 * c2) / (a2 * b1 * 2 - a1 * b2 * 2)};
	r = dis(a, o);
}
il void work()
{
	o = e[1], r = 0;
	for(int i=2;i<=n;i++)
	{
		if(dis(o, e[i]) > r + eps)
		{
			o = e[i], r = 0;
			for(int j=1;j<i-1;j++)
			{
				if(dis(o, e[j]) > r + eps)
				{
					o.x = (e[i].x + e[j].x) / 2;
					o.y = (e[i].y + e[j].y) / 2;
					r = dis(o, e[j]);
					for(int k=1;k<=j-1;k++)
						if(dis(o, e[k]) > r + eps) 
							get(e[i], e[j], e[k]);
 				}
			}
		}
	//	printf("%.10lf\n%.10lf %.10lf\n", r, o.x, o.y);
	}
}
int main()
{
	n = read();
	for(int i=1;i<=n;i++)scanf("%lf%lf", &e[i].x, &e[i].y);
    random_shuffle(e + 1, e + n + 1);
	work();
	printf("%.10lf\n%.10lf %.10lf", r, o.x, o.y);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值