题目链接:BZOJ - 3564
题目分析
求最小椭圆覆盖,题目给定了椭圆的长轴与 x 轴正方向的夹角,给定了椭圆长轴与短轴的比值。
那么先将所有点旋转一个角度,使椭圆长轴与 x 轴平行,再将所有点的 x 坐标除以长轴与短轴的比值,然后就直接做最小圆覆盖了。
随机增量法,一定别忘了 random_shuffle 。
代码
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
#define PI 3.14159265358979323846
#define Vector Point
typedef double LF;
const int MaxN = 50000 + 5;
const LF Eps = 1e-9;
int n;
LF Alpha, SinA, CosA;
struct Point
{
LF x, y;
Point() {}
Point(LF a, LF b)
{
x = a; y = b;
}
void Rotate(LF SinA, LF CosA)
{
LF tx, ty;
tx = CosA * x - SinA * y;
ty = SinA * x + CosA * y;
x = tx; y = ty;
}
} P[MaxN];
inline LF Sqr(LF x) {return x * x;}
inline LF Dis(Point p1, Point p2)
{
return sqrt(Sqr(p1.x - p2.x) + Sqr(p1.y - p2.y));
}
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);}
Point operator * (Point p, LF t) {return Point(p.x * t, p.y * t);}
Point operator / (Point p, LF t) {return Point(p.x / t, p.y / t);}
struct Line
{
Point p;
Vector v;
Line() {}
Line(Point p1, Point p2)
{
p = p1;
v = p2 - p1;
}
} L1, L2;
struct Circle
{
Point o;
LF r;
bool InCircle(Point p)
{
return Dis(o, p) <= r + Eps;
}
} C;
inline 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(u, l2.v) / Cross(l1.v, l2.v);
return l1.p + (l1.v * t);
}
Vector Turn90(Vector v)
{
return Vector(-v.y, v.x);
}
Line Verticle(Point p1, Point p2)
{
Line ret;
ret.p = (p1 + p2) / 2.0;
ret.v = Turn90(p2 - p1);
return ret;
}
int main()
{
srand(51405102);
scanf("%d", &n);
int a, b;
for (int i = 1; i <= n; ++i)
{
scanf("%d%d", &a, &b);
P[i] = Point((LF)a, (LF)b);
}
random_shuffle(P + 1, P + n + 1);
int ad, p;
scanf("%d", &ad);
Alpha = (LF)(-ad) / (LF)180 * PI;
SinA = sin(Alpha); CosA = cos(Alpha);
scanf("%d", &p);
for (int i = 1; i <= n; ++i)
{
P[i].Rotate(SinA, CosA);
P[i].x /= (LF)p;
}
C.o = P[1]; C.r = 0;
for (int i = 1; i <= n; ++i)
{
if (C.InCircle(P[i])) continue;
C.o = P[i]; C.r = 0;
for (int j = 1; j < i; ++j)
{
if (C.InCircle(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.InCircle(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("%.3lf\n", C.r);
return 0;
}