【SHTSC2014】信号增幅仪

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

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

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

Sample Input
Input1:

2
1 0
-1 0
0
2

Input2:

3
1 1
-1 -1
0 0
45
7

Sample Output
Output1:

0.500

Output2:

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

看到计算几何,感到莫名的兴奋,看到椭圆的一瞬间,哇天啊,没学过椭圆啊啊。。。
于是,我想方设法去判定点在椭圆内——到交点距离和小于某值。。。
焦点怎么求。。。

想了许久,发现事实上斜的椭圆可以看做一个圆横向伸长再旋转——这题切掉了——为我的zz感到无奈。。。

将椭圆旋转一个角度α判定,相当于将长轴水平的椭圆与点集旋转-α去判定。
判断一个水平的椭圆是否覆盖所有点,相当于将点集横向收缩,再判断一个圆是否覆盖所有点。

问题转换成,在向量旋转之后将x的坐标除以k后,点集的最小覆盖圆问题。
(不知道,旋转公式?①复数乘法②三角恒等变换的和差角公式)

最小圆覆盖问题,半径等于最远点对距离除以2!!当然是错的,等边三角形无法过。

引用RIA(求最小覆盖圆的随机增量法)

流程如下:
随机打乱顺序(十分重要)
①枚举i,求1~i的最小覆盖圆,到i时,1~i-1的最小覆盖圆已求出,若i不在其上,则i一定在1~i的最小覆盖圆上,令最终圆为圆心为i,半径为0,进入②,否则继续
②枚举再1~i-1间的第二个在1~i最小覆盖圆上的点,j,到j时,1~j-1与i的最小覆盖圆已确定,这时如果j不在覆盖圆中,则j一定是1~j与i的最小覆盖圆上的另一点,令最终圆为直径为ij的圆,进入③,否则继续
③1~j-1枚举第三个覆盖圆上的点,到k时,1~k-1,j,i的最小覆盖圆已求出,若k不在圆上,则i,j,k必是1~k,j,i的最小覆盖圆的三点,令最终圆为i,j,k的外接圆(并不需要判定i,j,k不共线,因为共线的话最终圆已被求出,并必包含i,j,k)。

复杂度好像是 O(n3) O ( n 3 )
注意到打乱顺序没?
大数据下,进入下一层的频率约为 3i 3 i
复杂度:
O1(n) O 1 ( n ) 为第一层复杂度, O2,O3 O 2 , O 3 同理

O1(n)O2(n)O3(n)=i=1ni3iO(1)+3iO2(i)=i=1ni3iO(n)+3iO3(i)=O(n)(1)(2)(3) (1) O 1 ( n ) = ∑ i = 1 n i − 3 i ∗ O ( 1 ) + 3 i ∗ O 2 ( i ) (2) O 2 ( n ) = ∑ i = 1 n i − 3 i ∗ O ( n ) + 3 i ∗ O 3 ( i ) (3) O 3 ( n ) = O ( n )

代入得
O2(n)O1(n)=O(n)=O(n)(4)(5) (4) O 2 ( n ) = O ( n ) (5) O 1 ( n ) = O ( n )

#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
#define db long double
#define N 50010

using namespace std;

int n,tot;
db ang,arc,k;

struct DOT{db x,y;}a[N],p[N],I;
bool cmp(DOT a,DOT b){return a.x<b.x || (a.x==b.x && a.y<b.y);}
struct CIRCLE{DOT o;db r;}o; 
struct LINE{DOT u,v;};

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,db b){return (DOT){a.x*b,a.y*b};}
DOT operator*(DOT a,DOT b){return (DOT){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};}
db dot(DOT a,DOT b){return a.x*b.x+a.y*b.y;}
db cro(DOT a,DOT b){return a.x*b.y-a.y*b.x;}
db len(DOT a){return sqrt(dot(a,a));}
DOT per(DOT a){return (DOT){a.y,-a.x};}
DOT inter(LINE a,LINE b){return b.u+b.v*(cro(a.v,a.u-b.u)/cro(a.v,b.v));}

bool in(DOT d){
    return len(d-o.o)<=o.r;
}

int main(){
    freopen("amplifier.in","r",stdin);
    freopen("amplifier.out","w",stdout);
    scanf("%d",&n);o=(CIRCLE){(DOT){0,0},0};
    for(int i=1;i<=n;i++)scanf("%Lf %Lf",&a[i].x,&a[i].y);
    scanf("%Lf",&ang);scanf("%Lf",&k);
    arc=ang*M_PI/180.0;I=(DOT){cos(arc),-sin(arc)};
    for(int i=1;i<=n;i++)a[i]=a[i]*I,a[i].x/=k;
    random_shuffle(a+1,a+n+1);
    for(int i=1;i<=n;++i)if(!in(a[i])){
        o=(CIRCLE){a[i],0.0};
        for(int j=1;j<i;++j)if(!in(a[j])){
            o=(CIRCLE){(a[i]+a[j])*0.5,len(a[i]-a[j])*0.5};
            for(int k=1;k<j;++k)if(!in(a[k])){
                LINE l1=(LINE){(a[i]+a[j])*0.5,per(a[j]-a[i])};
                LINE l2=(LINE){(a[i]+a[k])*0.5,per(a[k]-a[i])};
                DOT p=inter(l1,l2);o=(CIRCLE){p,len(p-a[i])};
            }
        }
    }
    printf("%.3Lf",o.r);
    fclose(stdin);fclose(stdout);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值