【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
同理
代入得
#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;
}