Description
无线网络基站在理想状况下有效信号覆盖范围是个圆形。而无线基站的功耗与圆的半径的平方成正比。现给出平面上若干网络用户的位置,请你选择一个合适的位置建设无线基站 ……
就在你拿起键盘准备开始敲代码的时候,你的好朋友发明家SHTSC突然出现了。SHTSC刚刚完成了他的新发明——无线信号增幅仪。增幅仪能够在不增加无线基站功耗的前提下,使得有效信号的覆盖范围在某一特定方向上伸长若干倍。即:使用了增幅仪的无线基站覆盖范围是个椭圆,其功耗正比于半短轴长的平方。
现给出平面上若干网络用户的位置,请你选择一个合适的位置建设无线基站,并在增幅仪的帮助下使所有的用户都能接收到信号,且无线基站的功耗最小。
注意:由于SHTSC增幅仪的工作原理依赖地磁场,增幅的方向是恒定的。
Input
第一行一个整数:\(n\)。平面内的用户个数。
之后的\(n\)行每行两个整数\(x, y\),表示一个用户的位置。
第\(n+2\)行一个整数:\(a\)。表示增幅仪的增幅方向,单位是度。表示增幅仪的方向是从\(x\)正方向逆时针转\(a\)度。
第\(n+3\)行一个整数:\(p\)。表示增幅仪的放大倍数。
Output
输出一行一个实数,为能够覆盖所有用户的最小椭圆的半短轴长,四舍五入到三位小数。
Analysis
这貌似超出我的能力范围。
对于一个平面直角坐标系上有\(n\)个点,求一个短半轴\(A=r\)、长半轴\(B=pr\)且长半轴所在直线为\(x\)轴逆时针旋转\(a^\circ\)的,\(r\)最小的能覆盖这\(n\)个点的椭圆。
(觉得难懂的话请自行脑补题面)
其实我们可以将所有元素顺时针旋转\(a^\circ\)。
再讲\(x\)轴的单位长度扩大为\(p\)。(即将所有点横坐标除以\(p\))
问题转化为最小覆盖圆问题。(蒟蒻水平有限,请自行百度)
跳转dalao‘s blog
Code
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define pi 3.14159265359
using namespace std;
struct Dot
{
double x, y;
Dot(double _x = 0, double _y = 0)
{
x = _x, y = _y;
}
};
struct Line
{
Dot p, v;
Line() {}
Line(Dot _p, Dot _v)
{
p = _p, v = _v;
}
};
int n;
double r;
Dot d[50005];
Dot core;
double a, p;
Dot operator+(Dot a, Dot b) {return Dot(a.x + b.x, a.y + b.y);}
Dot operator-(Dot a, Dot b) {return Dot(a.x - b.x, a.y - b.y);}
Dot operator*(Dot a, double b) {return Dot(a.x * b, a.y * b);}
double DotTimes(Dot a, Dot b) {return a.x * b.x + a.y * b.y;}
double CrossTimes(Dot a, Dot b) {return a.x * b.y - a.y * b.x;}
double Len(Dot t) {return sqrt(DotTimes(t, t));}
Dot Adjust(Dot a, double b) {return a * (b / Len(a));}
double Dist(Dot a, Dot b) {return Len(a - b);}
Dot Prep(Dot a) {return Dot(-a.y, a.x);}
Dot Intersect(Line a, Line b) {return b.p + b.v * (CrossTimes(a.v, a.p - b.p) / CrossTimes(a.v, b.v));}
Dot Angle(double a) {return Dot(cos(a), sin(a));}
Dot operator*(Dot a, Dot b) {return Dot(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);}
Dot Rotate(Dot a, double b) {return a * Angle(b);}
Dot Circumcenter(Dot a, Dot b, Dot c)
{
Line p = Line(a, b - a), q = Line(a, c - a);
p.p = p.p + p.v * 0.5, q.p = q.p + q.v * 0.5;
p.v = Prep(p.v), q.v = Prep(q.v);
return Intersect(p, q);
}
void Min_Cover_Circle()
{
random_shuffle(d + 1, d + n + 1);
Dot c;
c = d[1], r = 0;
for (int i = 2; i <= n; i++)
{
if (Dist(d[i], c) > r)
{
c = d[i]; r = 0;
for (int j = 1; j < i; j++)
if (Dist(d[j], c) > r)
{
c.x = (d[i].x + d[j].x) / 2;
c.y = (d[i].y + d[j].y) / 2;
r = Dist(d[j], c);
for (int k = 1; k < j; k++)
if (Dist(d[k], c) > r)
{
c = Circumcenter(d[i], d[j], d[k]);
r = Dist(d[i], c);
}
}
}
}
}
int main(int argc, char const *argv[])
{
freopen("init.in", "r", stdin);
//freopen("amplifier.out", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%lf%lf", &d[i].x, &d[i].y);
scanf("%lf%lf", &a, &p);
for (int i = 1; i <= n; i++)
{
d[i] = Rotate(d[i], (180 - a) * pi / 180);
d[i].x /= p;
}
Min_Cover_Circle();
printf("%.3lf\n", r);
return 0;
}