JZOJ-senior-3660. 【SHTSC2014】信号增幅仪(amplifier)

3660. 【SHTSC2014】信号增幅仪(amplifier)

(File IO): input:amplifier.in output:amplifier.out
Time Limits: 2000 ms Memory Limits: 262144 KB Detailed Limits

Description

无线网络基站在理想状况下有效信号覆盖范围是个圆形。而无线基站的功耗与圆的半径的平方成正比。现给出平面上若干网络用户的位置,请你选择一个合适的位置建设无线基站 ……

就在你拿起键盘准备开始敲代码的时候,你的好朋友发明家SHTSC突然出现了。SHTSC刚刚完成了他的新发明——无线信号增幅仪。增幅仪能够在不增加无线基站功耗的前提下,使得有效信号的覆盖范围在某一特定方向上伸长若干倍。即:使用了增幅仪的无线基站覆盖范围是个椭圆,其功耗正比于半短轴长的平方。

现给出平面上若干网络用户的位置,请你选择一个合适的位置建设无线基站,并在增幅仪的帮助下使所有的用户都能接收到信号,且无线基站的功耗最小。

注意:由于SHTSC增幅仪的工作原理依赖地磁场,增幅的方向是恒定的。

Input

第一行一个整数:n。平面内的用户个数。

之后的n行每行两个整数x, y,表示一个用户的位置。

第n+2行一个整数:a。表示增幅仪的增幅方向,单位是度。表示增幅仪的方向是从x正方向逆时针转a度。

第n+3行一个整数:p。表示增幅仪的放大倍数。

扫描二维码关注公众号,回复: 1826908 查看本文章

Output

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

Sample Input

输入1:

2

1 0

-1 0

0

2

输入2:

3

1 1

-1 -1

0 0

45

7

Sample Output

输出1:

0.500

输出2:

0.202

Data Constraint

对于10%的数据,保证最优方案的中心在原点。

对于20%的数据,保证点是随机生成的。

对于30%的数据,n≤100。

对于50%的数据,n≤5000。

对于100%的数据,n≤50000,0≤a<180,1≤p≤100,|x|,|y|≤2×10^8。

Solution

算法:最小圆覆盖模板

首先,这个椭圆是斜放的,所以我们需要套用坐标系旋转公式把它扳正

然后,这是个椭圆,要求它能够覆盖所有用户的最小椭圆的半短轴长并不容易,所以我们把它拍成圆形,即横坐标进行收缩,纵坐标不变,再进行最小圆覆盖

Code

#include<algorithm>
#include<cmath>
#include<cstdio>
#define N 50010
#define db double
#define sqr(x) ((x)*(x))
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
int n,i,j,k;
db a,r,p;
struct node
{
    db x,y;
}b[N],o;
node trans(node w)
{
    node q;
    q.x=w.x*cos(a)-w.y*sin(a);
    q.y=w.x*sin(a)+w.y*cos(a);
    return q;
}
db dist(node x,node y)
{
    return sqrt(sqr(x.x-y.x)+sqr(x.y-y.y));
}
bool in(node x)
{
    if (dist(o,x)>r) return 0;
    return 1;
}
int main()
{
    freopen("amplifier.in","r",stdin);
    freopen("amplifier.out","w",stdout);
    scanf("%d",&n);
    fo(i,1,n) scanf("%lf%lf",&b[i].x,&b[i].y);
    scanf("%lf%lf",&a,&p);
    random_shuffle(b+1,b+1+n);
    a=(360-a)*3.1415926535898/180;
    fo(i,1,n)
    {
        b[i]=trans(b[i]);
        b[i].x=b[i].x/p;
    }
    r=0;
    fo(i,1,n) if (!in(b[i]))
    {
        o.x=b[i].x;
        o.y=b[i].y;
        r=0;
        fo(j,1,i-1) if (!in(b[j]))
        {
            o.x=(b[i].x+b[j].x)/2;
            o.y=(b[i].y+b[j].y)/2;
            r=dist(o,b[i]);
            fo(k,1,j-1) if (!in(b[k]))
            {
                db A,B,C,G;
                db x1=b[i].x,y1=b[i].y;
                db x2=b[j].x,y2=b[j].y;
                db x3=b[k].x,y3=b[k].y;
                A=sqr(x1)+sqr(y1);
                B=sqr(x2)+sqr(y2);
                C=sqr(x3)+sqr(y3);
                G=(y3-y2)*x1+(y1-y3)*x2+(y2-y1)*x3;
                o.x=((B-C)*y1+(C-A)*y2+(A-B)*y3)/(2*G);
                o.y=((C-B)*x1+(A-C)*x2+(B-A)*x3)/(2*G);
                r=dist(b[i],o);
            }
        }
    }
    printf("%.3lf",r);
}

平面内坐标旋转公式

最小圆覆盖算法详解

猜你喜欢

转载自blog.csdn.net/huangxinyue1017/article/details/79251286