最小覆盖圆+定点旋转+C++三角函数使用 BZOJ信号增幅仪

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

输入格式:
第一行一个整数:n。平面内的用户个数。
之后的 n 行每行两个整数 x, y,表示一个用户的位置。
第 n+2 行一个整数:a。表示增幅仪的增幅方向,单位是度。表示增幅仪的方向是从 x 正方向逆时针转 a 度。
第 n+3 行一个整数:p。表示增幅仪的放大倍数。
输出格式:
输出一行一个实数,为能够覆盖所有用户的最小椭圆的半短轴长,四舍五入到三位小数。
样例输入:
3
1 1
-1 -1
0 0
45
7
样例输出:
0.202
数据范围:
对于 10%的数据,n≤5
对于 30%的数据,n≤50
对于 50%的数据,n≤200
对于 70%的数据,n≤1000
对于 100%的数据,n≤50000, 0≤a<180, 1≤p≤100, |x|,|y|≤2×108。
时间限制:
1s
空间限制:
256MB

本题是一道不错的计算几何题。先是一个特殊处理,把我们的坐标轴x轴转到 与增量方向一致(具体做法是往反方向旋转点),然后就可以直接把x轴除以该倍数就变成了一个圆,然后就是裸的最小圆覆盖。用随机迭代增量法找到最小覆盖圆,均摊复杂度O(n)
最小圆覆盖的方法已get就是三重循环好理解

今天还手证了一下一点绕定点旋转公式(不要怕设B∠)并手推了一下 三点确定圆心,圆的半径的做法.程序中要仔细看清楚,手推时要单独拉出来调程。
本题卡精度!!!!!!!!!!
C++三角函数pi 用acos(-1)得到。
C++内部三角函数用的都是弧度

#include<bits/stdc++.h>
using namespace std;
#define N 50001
struct NODE{
    double x,y;
}V[N];
double x,y,r;
double eps=1e-8;
int n;
#define F(i,a,b) for(int i=a;i<=b;i++)
double du;
const double pi=acos(-1);
double bei;
double dis(double x1,double y1,double x2,double y2)
{
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
} 
bool yuannei(NODE kk){return dis(kk.x,kk.y,x,y)-eps<=r;}
void solve(NODE a,NODE b,NODE c)
{
    double x1=a.x,x2=b.x,x3=c.x,y1=a.y,y2=b.y,y3=c.y;
    double a1,b1,c1,a2,b2,c2,a3,b3,c3;
    double xm,ym;
    xm=(x1+x2)/2;ym=(y1+y2)/2;
    a1=y2-y1;b1=x1-x2;swap(a1,b1);b1=-b1;c1=-(xm*a1+ym*b1);
    xm=(x1+x3)/2;ym=(y1+y3)/2;
    a2=y3-y1;b2=x1-x3;swap(a2,b2);b2=-b2;c2=-(xm*a2+ym*b2);
    x=(c2*b1-c1*b2)/(a1*b2-a2*b1);y=(-a1*x-c1)/b1;
    r=dis(a.x,a.y,x,y); 
}
NODE xuan(NODE o,double alpha,NODE p)
{
 NODE tp;
 p.x-=o.x;
 p.y-=o.y;
 tp.x=p.x*cos(alpha)-p.y*sin(alpha)+o.x+eps;
 tp.y=p.y*cos(alpha)+p.x*sin(alpha)+o.y+eps;//手推即可,beta最后会约掉 
 return tp;
}
int main()
{
    scanf("%d",&n);
    F(i,1,n){scanf("%lf%lf",&V[i].x,&V[i].y);}
    cin>>du>>bei;
    du=-du/180.0*pi;
    F(i,1,n)
    {
        NODE o;
        o.x=0;o.y=0;
        V[i]=xuan(o,du,V[i]);//每个点转负的,相当于坐标轴转正的。 
        V[i].x/=bei;
    } 
    random_shuffle(V+1,V+n+1);
    x=0;y=0;r=0;
    F(i,1,n)
    {
        if(!yuannei(V[i]))
        {
            x=V[i].x;y=V[i].y;r=0;
            F(j,1,i-1)
            {
                if(!yuannei(V[j]))
                {
                    x=(V[i].x+V[j].x)/2;y=(V[i].y+V[j].y)/2;
                    r=dis(V[i].x,V[i].y,x,y);
                    F(k,1,j-1)
                    {
                        if(!yuannei(V[k])) solve(V[i],V[j],V[k]);
                    }
                }
            }
        }
    }
    printf("%.3lf",r+eps);
    //要加个eps才能够A。 
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值