【AHOI2012】信号塔

题面

题解

xgzc怒切计算几何

最小圆覆盖板子题

整体算法如下:

枚举第一个点,考虑当前圆是否包含了这个点,如果没有,则把圆变成以这个点为圆心,半径为(0)的圆。再枚举第二个点,考虑圆是否包含了这个点,如果没有,则把圆变成以这两个点的中点为圆心,半径为两点距离一半的圆。再枚举第三个点,节点是否在圆内,如果不在,则把圆直接变成这三个点的外接圆。

(n^3)过百万???是的

我们随机打乱点,这样的期望是(O(n))

代码

#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<algorithm>
#define RG register
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define clear(x, y) memset(x, y, sizeof(x))

inline int read()
{
	int data = 0, w = 1; char ch = getchar();
	while(ch != '-' && (!isdigit(ch))) ch = getchar();
	if(ch == '-') w = -1, ch = getchar();
	while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
	return data * w;
}

const int maxn(1e6 + 10);
const double eps(1e-10), pi(acos(-1));
struct point { double x, y; };
struct line { point a, v; };
struct circle { point o; double r; } O;
typedef point vector;
inline vector operator + (const vector &lhs, const vector &rhs)
	{ return (vector) {lhs.x + rhs.x, lhs.y + rhs.y}; }
inline vector operator - (const vector &lhs, const vector &rhs)
	{ return (vector) {lhs.x - rhs.x, lhs.y - rhs.y}; }
inline vector operator * (const vector &lhs, const double &rhs)
	{ return (vector) {lhs.x * rhs, lhs.y * rhs}; }
inline vector operator / (const vector &lhs, const double &rhs)
	{ return (vector) {lhs.x / rhs, lhs.y / rhs}; }
inline double operator * (const vector &lhs, const vector &rhs)
	{ return lhs.x * rhs.x + lhs.y * rhs.y; }
inline double cross(const vector &lhs, const vector &rhs)
	{ return lhs.x * rhs.y - lhs.y * rhs.x; }
inline double Len(const vector &a) { return sqrt(a.x * a.x + a.y * a.y); }
inline double Dis(const point &a, const point &b) { return Len(a - b); }
inline vector rotate(const vector &lhs, const double &ang)
{
	double c = cos(ang), s = sin(ang);
	return (vector) {lhs.x * c - lhs.y * s, lhs.x * s + lhs.y * c};
}

point Intersection(const line &a, const line &b)
{
	vector c = b.a - a.a;
	double t = cross(b.v, c) / cross(b.v, a.v);
	return a.a + a.v * t;
}

line half(const line &a)
{
	point b = a.a + a.v * .5;
	return (line) {b, rotate(a.v, pi * .5)};
}

void getCircle(point p[], int n)
{
	std::random_shuffle(p + 1, p + n + 1);
	for(RG int i = 1; i <= n; ++i)
		if(Dis(O.o, p[i]) > O.r)
		{
			O.o = p[i], O.r = 0;
			for(RG int j = 1; j < i; j++)
				if(Dis(O.o, p[j]) > O.r)
				{
					O.o = (p[i] + p[j]) * .5, O.r = Dis(p[i], p[j]) * .5;
					for(RG int k = 1; k < j; k++)
						if(Dis(O.o, p[k]) > O.r)
							O.o = Intersection(half((line) {p[i], p[j] - p[i]}),
									half((line) {p[i], p[k] - p[i]})),
							O.r = Dis(O.o, p[i]);
				}
		}
	printf("%.2lf %.2lf %.2lf
", O.o.x, O.o.y, O.r);
}

int n; point p[maxn];
int main()
{
	srand(time(NULL)); scanf("%d", &n);
	for(RG int i = 1; i <= n; i++) scanf("%lf%lf", &p[i].x, &p[i].y);
	getCircle(p, n);
	return 0;
}
原文地址:https://www.cnblogs.com/cj-xxz/p/10336956.html