UOJ Logo zhouzixuan的博客

博客

bzoj 3564: [SHOI2014]信号增幅仪

2016-02-01 20:48:46 By zhouzixuan
【题目描述】:
    无线网络基站在理想状况下有效信号覆盖范围是个圆形。而无线基站的功耗与圆的半径的平方成正比。
现给出平面上若干网络用户的位置,请你选择一个合适的位置建设无线基站....
就在你拿起键盘准备开始敲代码的时候,你的好朋友发明家 SHTSC 突然出现了。SHTSC 刚刚完成了他的新发明——无线信号增幅仪。增幅仪能够在不增加无线基站功耗的前提下,使得有效信号的覆盖范围在某一特定方向上伸长若干倍。即:使用了增幅仪的无线基站覆盖范围是个椭圆,其功耗正比于半短轴长的平方。现给出平面上若干网络用户的位置,请你选择一个合适的位置建设无线基站,并在增幅仪的帮助下使所有的用户都能接收到信号,且无线基站的功耗最小。
    注意:由于SHTSC 增幅仪的工作原理依赖地磁场,增幅的方向是恒定的。
【题目解法】:
    显然最小椭圆覆盖是很难实现的
    我们可以把点顺时针旋转a度,然后x坐标缩短为1/p,就可以把覆盖变成圆形了
    然后就是最小圆覆盖了,模拟退火估计也是可以的
    复杂度O(N)
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <iomanip>
#define sqr(x) ((x)*(x))
using namespace std;
const int N=50005;
const long double zero=1e-8;
const long double pi=acos(-1.0);
struct node {long double x,y,r;} a[N];
struct line {long double A,B,C;};
int n; long double A,B; node ans;
inline long long getint()
{
    long long x=0; char c=getchar(); bool flag=false;
    while ((c!='-')&&((c<'0')||(c>'9'))) c=getchar();
    if (c=='-') flag=true,c=getchar();
    while ((c>='0')&&(c<='9')) x=x*10+(long long)(c-'0'),c=getchar();
    if (flag) return -x; else return x;
}
void init()
{
    n=getint();
    for (int i=1; i<=n; i++) cin >> a[i].x >> a[i].y;
    cin >> A; cin >> B; A=A*pi/180.0;
    /*
        x=rcosB y=rsinB
        x'=rcos(B-A)=rcosAcosB+rsinAsinB=xcosA+ysinA
        y'=rsin(B-A)=rsinBcosA-rsinAcosB=ycosA-xsinA
    */
    for (int i=1; i<=n; i++)
    {
        long double x=a[i].x,y=a[i].y; a[i].r=0;
        a[i].x=x*cos(A)+y*sin(A);
        a[i].y=y*cos(A)-x*sin(A);
        a[i].x/=B;
    }
}
inline int dcmp(long double x)
{
    if (x>zero) return 1;
    if (x<-zero) return -1;
    return 0;
}
inline long double dist(node A,node B)
{
    return sqrt(sqr(A.x-B.x)+sqr(A.y-B.y));
}
inline node centre(node A,node B)
{
    long double x=(A.x+B.x)/2,y=(A.y+B.y)/2;
    return (node){x,y,dist(A,B)/2};
}
inline line mid_vertical(node A,node B)
{
    //(B.x-A.x)/(A.y-B.y)*(x-x')+y'=y
    long double x=(A.x+B.x)/2,y=(A.y+B.y)/2; line now;
    now.A=B.x-A.x; now.B=B.y-A.y;
    now.C=-now.A*x-now.B*y; return now;
}
inline node centre(node A,node B,node C)
{
    line X=mid_vertical(A,B),Y=mid_vertical(B,C);
    if (X.A*Y.B==X.B*Y.A)
    {
        long double distAB=dist(A,B);
        long double distAC=dist(A,C);
        long double distBC=dist(B,C);
        long double dis=max(distAB,max(distAC,distBC));
        if (distAB==dis) return centre(A,B);
        if (distAC==dis) return centre(A,C);
        if (distBC==dis) return centre(B,C);
        return centre(A,B);
    }
    //a1x+b1y+c1=0->a1a2x+a2b1y+a2c1=0
    //a2x+b2y+c2=0->a1a2x+a1b2y+a1c2=0
    node now;
    now.y=(X.A*Y.C-X.C*Y.A)/(Y.A*X.B-X.A*Y.B);
    now.x=(-X.C-X.B*now.y)/X.A;
    now.r=dist(now,A); return now;
}
void solve()
{
    ans=a[1]; ans.r=0;
    for (int i=2; i<=n; i++)
    {
        if (dcmp(dist(ans,a[i])-ans.r)<=0) continue;
        ans=a[i]; ans.r=0;
        for (int j=1; j<i; j++)
        {
            if (dcmp(dist(ans,a[j])-ans.r)<=0) continue;
            ans=centre(a[i],a[j]);
            for (int k=1; k<j; k++)
            {
                if (dcmp(dist(ans,a[k])-ans.r)<=0) continue;
                ans=centre(a[i],a[j],a[k]);
            }
        }
    }
    cout << fixed << setprecision(3) << ans.r;
}
int main()
{
    init();
    solve();
    return 0;
}

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。