Processing math: 100%

P1742 最小圆覆盖(计算几何)

体验过O(n3)105吗?快来体验一波当wys的快感吧QAQ

前置芝士1:二元一次方程组求解

{a1x+b1y=c1a2x+b2y=c2

(其中a1,a2,b1,b2,c1,c2为已知量)

式得:

x=c2b2ya2

带入式并化简得:

y=c1a1c2a2b1a1b2a2

分子分母同时乘以a2得:

y=a2c1a1c2a2b1a1b2

同理可得(把a,b互换即可):

x=b2c1b1c2b2a1b1a2

前置芝士2:三点定圆

给出三个点,求出圆心&半径

{x122x1x0+x02+y122y1y0+y02=r2x222x2x0+x02+y222y2y0+y02=r2x322x3x0+x02+y322y3y0+y02=r2

,并化简得:

{2(x2x1)x+2(y2y1)y=x22x12+y22y122(x3x1)x+2(y3y1)y=x32x12+y32y12

我们将三点定圆的柿子对应二元一次方程组中,可知:

a1=x2x1,a2=x3x1

b1=y2y1,b2=y3y1

c1=x22x12+y22y122,c2=x32x12+y32y122

然后就可以根据三个点求出圆心和半径了

正文

跟据前置芝士,我们知道对于任意三个不共线的点,我们可以求出三点定的圆,所以一个明显的想法就是枚举三个点

我们先枚举第一个点,有两种情况

①:当前点在当前外面,即dis(圆心,该点)>r那么我们不管这个点

②:不是情况①的情况,那么我们就需要重新构造这个圆来包含所有的点了

怎么构造呢?我们重新枚举两外两个已经遍历过的点,组成三个点。同理,若重新构造的圆包括了三个点,那么就不管,若有任意一个在圆外,那么我们根据前置芝士重新确定圆心和半径即可

PS:本题出题人过于duliu,故意构造数据卡掉了上述解法,所以我们需要一个神奇的东西:随(da)(luan)(shu)(ju)法,来防止掉精度

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define re register
#define D double
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 rep(i, s, t) for(re int i = s; i <= t; ++ i)
#define eps 1e-12
#define maxn 100005
#define ff(x) (x) * (x)
int n, m;
D r;
struct node
{
	D x, y;
}o, e[maxn];
il D 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)
{
	D a1 = b.x - a.x, a2 = c.x - a.x, b1 = b.y - a.y, b2 = c.y - a.y;
	D c1 = (ff(b.x) - ff(a.x) + ff(b.y) - ff(a.y));
	D 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;
	rep(i, 2, n)
	{
		if(dis(o, e[i]) > r + eps)
		{
			o = e[i], r = 0;
			rep(j, 1, i - 1)
			{
				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]);
					rep(k, 1, j - 1) 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();
	rep(i, 1, n) 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;
}
posted @   呢没理他  阅读(389)  评论(0编辑  收藏  举报
编辑推荐:
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
阅读排行:
· [翻译] 为什么 Tracebit 用 C# 开发
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· DeepSeek崛起:程序员“饭碗”被抢,还是职业进化新起点?
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端
点击右上角即可分享
微信分享提示