您的位置:首页 > 其它

JZOJ 3660. 【SHTSC2014】信号增幅仪

2018-01-31 22:07 316 查看

Description

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

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

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

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

Input

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

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

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

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

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

发现被拉长的“椭圆”和角度问题导致我们很难去统计答案。

考虑简化它!

我们可以将角度 a 转正,再将每个点的纵坐标缩小 p 倍。

新的点的坐标可以通过三角函数的运算得出(画个图很好理解)。

这样就可以用一个正常的圆来覆盖这些点了,经典的最小圆覆盖问题。

现将点随机顺序,枚举每个点,在当前圆内就不管它。

若超出当前圆,则说明该点在新圆的边上。

以两点连线的中点作为新的圆的圆心,再继续枚举点。

若还是超出,则说明该点也在新圆的边上。

此时有三个点都在圆的边上,“三点确定一个圆”。

作出两条中垂线,再求其交点即可。

神奇的是,看上去是三重循环,但可证其时间复杂度是 O(N) 的。

Code

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cctype>
using namespace std;
const int N=50005;
const double Pi=acos(-1);
struct node
{
double x,y;
}a
,t,O;
double R;
inline int read()
{
int X=0,w=0; char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
inline double sqr(double x)
{
return x*x;
}
inline double dist(node x,node y)
{
return sqrt(sqr(x.x-y.x)+sqr(x.y-y.y));
}
inline bool incircle(node x)
{
return dist(O,x)<=R;
}
inline node midpoint(node x,node y)
{
t.x=(x.x+y.x)/2.0;
t.y=(x.y+y.y)/2.0;
return t;
}
inline void get(double &x,double &y,double &z,node xx,node yy)
{
if(xx.y==yy.y)
{
x=1.0,y=0.0,z=-(xx.x+yy.x)/2.0;
}else
if(xx.x==yy.x)
{
x=0.0,y=1.0,z=-(xx.y+yy.y)/2.0;
}else
{
t=midpoint(xx,yy);
double k=-1.0/((xx.y-yy.y)*1.0/(xx.x-yy.x));
x=k,y=-1.0,z=t.y-k*t.x;
}
}
inline node work(node xx,node yy,node zz)
{
double a1=0,b1=0,c1=0,a2=0,b2=0,c2=0;
get(a1,b1,c1,xx,yy);
get(a2,b2,c2,yy,zz);
t.y=-(a2*c1-a1*c2)/(b1*a2-b2*a1);
t.x=(-c1-b1*t.y)/a1;
return t;
}
int main()
{
int n=read();
for(int i=1;i<=n;i++) a[i].x=read(),a[i].y=read();
double d=read()/180.0*Pi,p=read();
if(!d)
{
for(int i=1;i<=n;i++)
{
swap(a[i].x,a[i].y);
a[i].x=-a[i].x;
a[i].y=a[i].y*1.0/p;
}
}else
if(d==Pi/2.0)
{
for(int i=1;i<=n;i++) a[i].y=a[i].y*1.0/p;
}else
{
double si=sin(d),co=cos(d),ta=tan(d);
for(int i=1;i<=n;i++)
{
double z=a[i].x-a[i].y/ta;
t.x=z*si;
t.y=a[i].y/si+z*co;
t.y=t.y*1.0/p;
a[i]=t;
}
}
random_shuffle(a+1,a+1+n);
for(int i=1;i<=n;i++)
if(!incircle(a[i]))
{
O=a[i],R=0;
for(int j=1;j<i;j++)
if(!incircle(a[j]))
{
O=midpoint(a[i],a[j]);
R=dist(O,a[i]);
for(int k=1;k<j;k++)
if(!incircle(a[k]))
{
O=work(a[i],a[j],a[k]);
R=dist(O,a[i]);
}
}
}
printf("%.3lf",R);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: