[BZOJ 1336] [Balkan2002] Alien最小圆覆盖 【随机增量法】
题目链接:BZOJ - 1336
题目分析
最小圆覆盖有一个算法叫做随机增量法,看起来复杂度像是 O(n^3) ,但是可以证明其实平均是 O(n) 的,至于为什么我不知道= =
为什么是随机呢?因为算法进行前要将所有的点 random_shuffle 一次。为什么要这样做呢?因为这样就可以防止出题人用最坏情况卡掉增量算法。
这和随机化快排使用随机是一个道理。
算法步骤:
random_shuffle n 个点
将圆设定为以 P[1] 为圆心,以 0 为半径
for i : 1 to n
{
if (P[i] 不在圆内)
{
将圆设定为以 P[i] 为圆心,以 0 为半径
for j : 1 to i - 1
{
if (P[j] 不在圆内)
{
将圆设定为以 P[i]P[j] 为直径
for k : 1 to j - 1
{
if (P[k] 不在圆内)
{
将圆设定为 P[i],P[j],P[k] 的外接圆
}
}
}
}
}
}
代码
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define Vector Point
typedef double LF;
const int MaxN = 100000 + 5;
const LF Eps = 1e-12;
int n;
struct Point
{
LF x, y;
Point() {}
Point(LF a, LF b)
{
x = a; y = b;
}
} P[MaxN];
Point operator + (Point p1, Point p2)
{
return Point(p1.x + p2.x, p1.y + p2.y);
}
Point operator - (Point p1, Point p2)
{
return Point(p1.x - p2.x, p1.y - p2.y);
}
Vector operator * (Vector v, LF t)
{
return Vector(v.x * t, v.y * t);
}
Vector operator / (Vector v, LF t)
{
return Vector(v.x / t, v.y / t);
}
inline LF Sqr(LF x) {return x * x;}
inline LF gmax(LF a, LF b) {return a > b ? a : b;}
inline LF Dis(Point p1, Point p2)
{
return sqrt(Sqr(p1.x - p2.x) + Sqr(p1.y - p2.y));
}
struct Circle
{
Point o;
LF r;
Circle() {}
Circle(Point a, LF b)
{
o = a; r = b;
}
bool Inside(Point p)
{
return Dis(p, o) - r <= Eps;
}
} C;
struct Line
{
Point p;
Vector v;
Line() {}
Line(Point a, Vector b)
{
p = a; v = b;
}
} L1, L2;
LF Cross(Vector v1, Vector v2)
{
return v1.x * v2.y - v2.x * v1.y;
}
Point Intersection(Line l1, Line l2)
{
Vector u = l2.p - l1.p;
LF t = Cross(l2.v, u) / Cross(l2.v, l1.v);
return l1.p + (l1.v * t);
}
Vector Change(Vector v)
{
return Vector(-v.y, v.x);
}
Line Verticle(Point p1, Point p2)
{
Line ret;
ret.p = (p1 + p2) / 2.0;
ret.v = Change(p2 - p1);
return ret;
}
int main()
{
srand(19981014);
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
scanf("%lf%lf", &P[i].x, &P[i].y);
random_shuffle(P + 1, P + n + 1);
C.o = P[1];
C.r = 0;
for (int i = 1; i <= n; ++i)
{
if (C.Inside(P[i])) continue;
C.o = P[i]; C.r = 0;
for (int j = 1; j < i; ++j)
{
if (C.Inside(P[j])) continue;
C.o = (P[i] + P[j]) / 2.0;
C.r = Dis(C.o, P[j]);
for (int k = 1; k < j; ++k)
{
if (C.Inside(P[k])) continue;
L1 = Verticle(P[i], P[k]);
L2 = Verticle(P[j], P[k]);
C.o = Intersection(L1, L2);
C.r = Dis(C.o, P[k]);
}
}
}
printf("%.10lf\n%.10lf %.10lf\n", C.r, C.o.x, C.o.y);
return 0;
}

浙公网安备 33010602011771号