码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2018-02-04 12:46:45      阅读:186      评论:0      收藏:0      [点我收藏+]

标签:依赖   markdown   inter   mat   功耗   shuf   name   out   stdout   

题目空降

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;
}

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

标签:依赖   markdown   inter   mat   功耗   shuf   name   out   stdout   

原文地址:https://www.cnblogs.com/Ace-Killing/p/JAN31_A_T2.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!