January 31st 模拟赛A T2 【SHTSC2014】信号增幅仪 Solution

题目空降

Description

无线网络基站在理想状况下有效信号覆盖范围是个圆形。而无线基站的功耗与圆的半径的平方成正比。现给出平面上若干网络用户的位置,请你选择一个合适的位置建设无线基站 ……
就在你拿起键盘准备开始敲代码的时候,你的好朋友发明家SHTSC突然出现了。SHTSC刚刚完成了他的新发明——无线信号增幅仪。增幅仪能够在不增加无线基站功耗的前提下,使得有效信号的覆盖范围在某一特定方向上伸长若干倍。即:使用了增幅仪的无线基站覆盖范围是个椭圆,其功耗正比于半短轴长的平方。
现给出平面上若干网络用户的位置,请你选择一个合适的位置建设无线基站,并在增幅仪的帮助下使所有的用户都能接收到信号,且无线基站的功耗最小。
注意:由于SHTSC增幅仪的工作原理依赖地磁场,增幅的方向是恒定的。

Input

第一行一个整数: n n 。平面内的用户个数。
之后的n行每行两个整数 x,y x , y ,表示一个用户的位置。
n+2 n + 2 行一个整数: a a 。表示增幅仪的增幅方向,单位是度。表示增幅仪的方向是从x正方向逆时针转 a a 度。
n+3行一个整数: p p 。表示增幅仪的放大倍数。

Output

输出一行一个实数,为能够覆盖所有用户的最小椭圆的半短轴长,四舍五入到三位小数。

Analysis

貌似超出我的能力范围。
对于一个平面直角坐标系上有n个点,求一个短半轴 A=r A = r 、长半轴 B=pr B = p r 且长半轴所在直线为 x x 轴逆时针旋转a的, r r 最小的能覆盖这n个点的椭圆。
(觉得难懂的话请自行脑补题面)
这里写图片描述
其实我们可以将所有元素顺时针旋转 a a ∘
这里写图片描述
再讲 x x 轴的单位长度扩大为p(即将所有点横坐标除以 p p <script type="math/tex" id="MathJax-Element-306">p</script>)
这里写图片描述
问题转化为最小覆盖圆问题。(蒟蒻水平有限,请自行百度)
跳转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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值