期望复杂度O(n)
原理与最小圆覆盖类似,只是要多求一个四面体的外接圆。
坑点:poj不能srand(time(NULL)),会RE
代码:
#include <cstdio>
#include <cmath>
#include <limits>
#include <algorithm>
#include <ctime>
using namespace std;
#define MAXN 111
template <typename T>
(T x) {
T sqreturn x * x;
}
const double eps = 1e-12, pi = acos(-1.0);
int sgn(double x) {
return fabs(x) < eps ? 0 : (x < 0 ? -1 : 1);
}
struct VEC {
double x, y, z;
operator + (const VEC& b) const {
VEC return VEC{x + b.x, y + b.y, z + b.z};
}
operator - (const VEC& b) const {
VEC return VEC{x - b.x, y - b.y, z - b.z};
}
double len2() const {
return sq(x) + sq(y) + sq(z);
}
double len() const {
return sqrt(len2());
}
double dist2(const VEC& b) const {
return (*this - b).len2();
}
double dist(const VEC& b) const {
return (*this - b).len();
}
operator * (double b) const {
VEC return VEC{x * b, y * b, z * b};
}
(double l) const {
VEC truncdouble ori = len();
if (!sgn(ori)) return *this;
return *this * (l / ori);
}
operator / (double b) const {
VEC return VEC{x / b, y / b, z / b};
}
() const {
VEC normreturn *this / len();
}
operator ^ (const VEC& b) const {
VEC return VEC{y * b.z - b.y * z, b.x * z - x * b.z, x * b.y - b.x * y};
}
double operator * (const VEC& b) const {
return x * b.x + y * b.y + z * b.z;
}
double rad(const VEC& b) const {
return fabs(atan2((*this ^ b).len(), *this * b));
}
double rad_acos(const VEC& b) const {
double L1 = len2(), L2 = b.len2();
return acos((L1 + L2 - (*this - b).len2()) / (2 * sqrt(L1) * sqrt(L2)));
}
double MixedProd(const VEC& b, const VEC& c) const {
return *this * (b ^ c);
}
void input() {
("%lf%lf%lf", &x, &y, &z);
scanf}
};
struct LINE {
, v;
VEC sdouble dist(const VEC& p) const {
return (v ^ (p - s)).len() / v.len();
}
(const VEC& p) const {
VEC projection= v.norm();
VEC v1 return v1 * ((p - s) * v1) + s;
}
};
struct CIRCLE3 {
, v;
VEC cdouble r;
};
struct BALL {
;
VEC cdouble r;
bool operator == (const BALL& b) const {
return sgn((c - b.c).len()) == 0 && sgn(r - b.r) == 0;
}
//1: inside
//2: internally tangent
//3: Cross
//4: externally tangent
//5: away from
int relation(const BALL& b) const {
double d = c.dist(b.c);
int s = sgn(d - fabs(b.r - r));
if (s <= 0) return s + 2;
return sgn(d - (b.r + r)) + 4;
}
//-1: inside
//0: on
//1: out
int relation(const VEC& p) const {
return sgn(p.dist(c) - r);
}
//-1: infinite
int cross(CIRCLE3& ans, const BALL& b) const {
int rel = relation(b);
if (rel == 1 || rel == 5) return 0;
if (*this == b) return -1;
.v = (b.c - c).norm();
ans//WA ???? poj 2177
//double d2 = c.dist2(b.c);
//double l = (sq(r) + d2 - sq(b.r)) / (2 * sqrt(d2)); //projection of r on d
double d = c.dist(b.c);
double l = (sq(r) + sq(d) - sq(b.r)) / (2 * d);
.c = c + ans.v * l;
ans.r = sqrt(sq(r) - sq(l));
ansreturn 1;
}
void SetCircumscribed(const VEC& A, const VEC& B) {
= (A + B) / 2.0;
c = (B - A).len() / 2.0;
r }
//outer
//Make sure that A, B, C are not collinear
void SetCircumscribed(const VEC& A, VEC B, VEC C) {
= B - A;
B = C - A;
C = B ^ C;
VEC s2di if (s2di.len() < eps) return;
= s2di ^ B;
VEC abv = C ^ s2di;
VEC acv = (abv * C.len2() + acv * B.len2()) / (2.0 * s2di.len2());
VEC to = A + to;
c = to.len();
r }
//Make sure that A, B, C, D are not in the same plane
void SetCircumscribed(const VEC& A, const VEC& B, const VEC& C, VEC D) {
(A, B, C);
SetCircumscribed= ((C - A) ^ (B - A)).norm();
VEC v = D - c;
D double L = D * v, d2 = (v ^ D).len2();
if (fabs(L) < eps) return;
double k = (d2 + sq(L) - sq(r)) / (2 * L);
= c + v * k;
c = sqrt(sq(k) + sq(r));
r }
};
(VEC ps[], int n) {
BALL SmallestBallCover(ps, ps + n);
random_shuffle{ps[0], 0};
BALL ballfor (int i1 = 1; i1 < n; ++i1) {
if (ball.relation(ps[i1]) == 1) {
.c = ps[i1];
ballfor (int i2 = 0; i2 < i1; ++i2) {
if (ball.relation(ps[i2]) == 1) {
.SetCircumscribed(ps[i1], ps[i2]);
ballfor (int i3 = 0; i3 < i2; ++i3) {
if (ball.relation(ps[i3]) == 1) {
.SetCircumscribed(ps[i1], ps[i2], ps[i3]);
ballfor (int i4 = 0; i4 < i3; ++i4) {
if (ball.relation(ps[i4]) == 1) {
.SetCircumscribed(ps[i1], ps[i2], ps[i3], ps[i4]);
ball}
}
}
}
}
}
}
}
return ball;
}
int main() {
int n;
static VEC ps[MAXN];
//srand(time(NULL));
(19990828);
srand
while (~scanf("%d", &n) && n) {
for (int i = 0; i < n; ++i) {
[i].input();
ps}
= SmallestBallCover(ps, n);
BALL ans ("%.5f\n", ans.r);
printf}
return 0;
}