zoukankan      html  css  js  c++  java
  • BZOJ 3564: [SHOI2014]信号增幅仪 最小圆覆盖

    3564: [SHOI2014]信号增幅仪

    题目连接:

    http://www.lydsy.com/JudgeOnline/problem.php?id=3564

    Description

    无线网络基站在理想状况下有效信号覆盖范围是个圆形。而无线基站的功耗与圆的半径的平方成正比。
    现给出平面上若干网络用户的位置,请你选择一个合适的位置建设无线基站....
    就在你拿起键盘准备开始敲代码的时候,你的好朋友发明家 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
    ",r);
    }
  • 相关阅读:
    《Intel汇编第5版》 汇编逆转字符串
    《Intel汇编第5版》 汇编拷贝字符串
    《Intel汇编第5版》 数组求和
    《Intel汇编第5版》 Mov指令
    CABasicAnimation 几种停止的回调
    模拟器SDK路径
    《Intel汇编第5版》 Intel CPU小端序
    《Intel汇编第5版》 汇编减法程序
    Iphone CPU 架构类型
    越狱开发-创建真正的后台程序(Daemon Process)
  • 原文地址:https://www.cnblogs.com/qscqesze/p/5748127.html
Copyright © 2011-2022 走看看