BZOJ 3564: [SHOI2014]信号增幅仪 最小圆覆盖
2016-08-08 09:49
309 查看
3564: [SHOI2014]信号增幅仪
题目连接:
http://www.lydsy.com/JudgeOnline/problem.php?id=3564Description
无线网络基站在理想状况下有效信号覆盖范围是个圆形。而无线基站的功耗与圆的半径的平方成正比。现给出平面上若干网络用户的位置,请你选择一个合适的位置建设无线基站....
就在你拿起键盘准备开始敲代码的时候,你的好朋友发明家 SHTSC 突然出现了。SHTSC 刚刚完成了他的新发明——无线信号增幅仪。增幅仪能够在不增加无线基站功耗的前提下,使得有效信号的覆盖范围在某一特定方向上伸长若干倍。即:使用了增幅仪的无线基站覆盖范围是个椭圆,其功耗正比于半短轴长的平方。现给出平面上若干网络用户的位置,请你选择一个合适的位置建设无线基站,并在增幅仪的帮助下使所有的用户都能接收到信号,且无线基站的功耗最小。
注意:由于SHTSC 增幅仪的工作原理依赖地磁场,增幅的方向是恒定的。
Input
第一行一个整数:n。平面内的用户个数。之后的 n 行每行两个整数 x, y,表示一个用户的位置。
第 n+2 行一个整数:a。表示增幅仪的增幅方向,单位是度。表示增幅仪的方向是从 x 正方向逆时针转 a 度。
第 n+3 行一个整数:p。表示增幅仪的放大倍数。
Output
输出一行一个实数,为能够覆盖所有用户的最小椭圆的半短轴长,四舍五入到三位小数。Sample Input
样例一:2
1 0
-1 0
0
2
样例二:
3
1 1
-1 -1
0 0
4 5
7
Sample Output
样例一:0.500
样例二:
0.202
Hint
对于 100%的数据,n≤50000,0≤a<180,1≤p≤100,|x|,|y|≤2×10^8。题意
题解:
椭圆的话,先把所有点都旋转一下,使得椭圆的长轴在x轴上面。然后再让所有点都缩小放大的倍数,那么这道题就可以转化为最小圆覆盖了。
然后跑随机增量法就好了。
代码
#include<bits/stdc++.h> using namespace std; const int maxn = 50005; const double pi = acos(-1.0); const double EP = 1E-6; struct POINT { double x; double y; POINT(double a=0, double b=0) { x=a; y=b;} //constructor }; POINT operator +(POINT p1,POINT p2){ return POINT(p1.x+p2.x,p1.y+p2.y); } POINT operator -(POINT p1,POINT p2){ return POINT(p1.x-p2.x,p1.y-p2.y); } double operator *(POINT p1,POINT p2){ return p1.x*p2.y-p1.y*p2.x; } POINT operator /(POINT p1,double x){ return POINT(p1.x/x,p1.y/x); } POINT operator *(POINT p,double x){ return POINT(p.x*x,p.y*x); } struct LINESEG { POINT s; POINT e; LINESEG(POINT a, POINT b) { s=a; e=b;} LINESEG() { } }; struct LINE // 直线的解析方程 a*x+b*y+c=0 为统一表示,约定 a >= 0 { double a; double b; double c; LINE(double d1=1, double d2=-1, double d3=0) {a=d1; b=d2; c=d3;} }; // 返回点p以点o为圆心逆时针旋转alpha(单位:弧度)后所在的位置 POINT rotate(POINT o,double alpha,POINT p) { POINT tp; p.x-=o.x; p.y-=o.y; tp.x=p.x*cos(alpha)-p.y*sin(alpha)+o.x; tp.y=p.y*cos(alpha)+p.x*sin(alpha)+o.y; return tp; } int n; POINT po[maxn],O; double r; double dis(POINT A,POINT B){ return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)); } POINT circumcenter(const POINT &a,const POINT &b,const POINT &c) { //返回三角形的外心 POINT ret; double a1=b.x-a.x,b1=b.y-a.y,c1=(a1*a1+b1*b1)/2.0; double a2=c.x-a.x,b2=c.y-a.y,c2=(a2*a2+b2*b2)/2.0; double d=a1*b2-a2*b1; ret.x=a.x+(c1*b2-c2*b1)/d; ret.y=a.y+(a1*c2-a2*c1)/d; return ret; } void min_cover_circle(POINT *p,int n,POINT &c,double &r){ //c为圆心,r为半径 random_shuffle(p,p+n); // c=p[0]; r=0; for(int i=1;i<n;i++) { if(dis(p[i],c)>r+EP) //第一个点 { c=p[i]; r=0; for(int j=0;j<i;j++) if(dis(p[j],c)>r+EP) //第二个点 { c.x=(p[i].x+p[j].x)/2; c.y=(p[i].y+p[j].y)/2; r=dis(p[j],c); for(int k=0;k<j;k++) if(dis(p[k],c)>r+EP) //第三个点 {//求外接圆圆心,三点必不共线 c=circumcenter(p[i],p[j],p[k]); r=dis(p[i],c); } } } } } int main(){ srand(772002); scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%lf%lf",&po[i].x,&po[i].y); } double a,p; scanf("%lf%lf",&a,&p); double ang=-a/180.0*pi; for(int i=0;i<n;i++){ po[i]=rotate(POINT(0,0),ang,po[i]); po[i].x/=p; } min_cover_circle(po,n,O,r); printf("%.3f\n",r); }
相关文章推荐
- BZOJ 3564 SHOI 2014 信号增幅仪 坐标变换+最小圆覆盖
- [BZOJ 3564] [SHOI2014] 信号增幅仪 【最小圆覆盖】
- BZOJ 3564: [SHOI2014]信号增幅仪(随机增量法)
- BZOJ3564 : [SHOI2014]信号增幅仪
- BZOJ3564 [SHOI2014]信号增幅仪
- bzoj3564 信号增幅仪【最小圆覆盖+坐标变换】
- bzoj3564[SHOI2014]信号增幅仪
- BZOJ 3564 SHOI2014 信号增幅仪 随机增量法
- BZOJ 3564: [SHOI2014]信号增幅仪
- 最小覆盖圆+定点旋转+C++三角函数使用 BZOJ信号增幅仪
- bzoj3564: [SHOI2014]信号增幅仪
- bzoj3564: [SHOI2014]信号增幅仪 最小圆覆盖
- 【bzoj3564】 [SHOI2014]信号增幅仪
- BZOJ 3564 信号增幅仪
- 【BZOJ 2823】【AHOI2012】【最小圆覆盖模板题】信号塔
- bzoj-3564 信号增幅仪
- BZOJ3564 信号增幅仪
- bzoj 3566 [SHOI2014]概率充电器 概率dp
- [bzoj1336][最小圆覆盖]Alien最小圆覆盖
- 【bzoj 1934】[Shoi2007]Vote 善意的投票 最小割