jzoj 3660. 【SHTSC2014】信号增幅仪

本文探讨了如何在平面上选择无线基站位置并利用定向增幅技术实现信号全覆盖的问题。通过旋转坐标系、调整用户位置坐标并应用随机增量法来确定覆盖所有用户的最小椭圆,从而确保基站功耗最低。

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。


Sulotion

因为只有固定的方向才能增幅,而结果为椭圆,于是我们可以把它缩放为增幅前的圆,
所以先旋转a度(用三角函数要转弧度),然后每个点横坐标除以p,最后最小圆覆盖。
最小圆覆盖的方法:随机增量法 http://blog.youkuaiyun.com/commonc/article/details/52291822(非常详细且证明了时间复杂度期望为O(n))
及已知三点求外接圆的方法 http://blog.youkuaiyun.com/liyuanbhu/article/details/52891868

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;

#define N 50050
#define DB double
#define pi 3.1415926535897932384626433832795

struct note
{
    DB x,y;
};

note a[N];
DB al,th,p,co,si,ans,s;
int n; 

DB sqr(DB x){return x*x;}
DB dis(note x,note y){return sqrt(sqr(x.x-y.x)+sqr(x.y-y.y));}
bool pd(int x) {return dis(a[0],a[x])<=s;} 

void init()
{
    scanf("%d",&n);
    int x,y;
    for (int i=1;i<=n;i++)
    {
        scanf("%d%d",&x,&y);
        a[i].x=DB(x); a[i].y=DB(y);
    }
    scanf("%d%d",&x,&y);
    al=DB(x); p=DB(y);
    th=al*pi/180.00000;
    si=sin(th); co=cos(th);
    DB xx,yy;
    for (int i=1;i<=n;i++)
    {
        xx=a[i].x; yy=a[i].y;
        a[i].x=si*yy+co*xx;
        a[i].y=co*yy-si*xx;
        a[i].x/=p;
    }
}

note solve(note x,note y,note z)
{
    DB a,b,c,d,e,f;
    a=x.x-y.x; b=x.y-y.y; c=x.x-z.x; d=x.y-z.y;
    e=sqr(x.x)-sqr(y.x)+sqr(x.y)-sqr(y.y);  e/=2;
    f=sqr(x.x)-sqr(z.x)+sqr(x.y)-sqr(z.y);  f/=2;
    note re;
    re.x=-(d*e-b*f)/(b*c-a*d);
    re.y=-(a*f-c*e)/(b*c-a*d);
    return re;
}

void find()
{
    random_shuffle(a+1,a+n+1);
    for (int i=1;i<=n;i++)
      if (pd(i)==false)
      {
        a[0]=a[i]; s=0.0;
        for (int j=1;j<=i-1;j++)
          if (pd(j)==false)
          {
            a[0].x=(a[i].x+a[j].x)/2; a[0].y=(a[i].y+a[j].y)/2;
            s=dis(a[i],a[j])/2;
            for (int k=1;k<=j-1;k++)
              if (pd(k)==false)
              {
                a[0]=solve(a[i],a[j],a[k]);
                s=dis(a[0],a[i]);
              }
          }
      }
}

int main()
{
    freopen("amplifier.in","r",stdin);
    freopen("amplifier.out","w",stdout);
    init();
    find();
    ans=s;
    printf("%.3lf\n",ans);
    return 0;
}
曾经发明了信号增幅的发明家 SHTSC 又公开了他的新发明:自动刷题机——一种可以自动 AC 题目的神秘装置。 自动刷题机刷题的方式非常简单:首先会瞬间得出题目的正确做法,然后开始写程序。每秒,自动刷题机的代码生成模块会有两种可能的结果: 写了 x x 行代码 心情不好,删掉了之前写的 y y 行代码。(如果 y y 大于当前代码长度则相当于全部删除。) 对于一个 OJ,存在某个固定的正整数长度 n n,一旦自动刷题机在某秒结束时积累了大于等于 n n 行的代码,它就会自动提交并 AC 此题,然后新建一个文件(即弃置之前的所有代码)并开始写下一题。SHTSC 在某个 OJ 上跑了一天的自动刷题机,得到了很多条关于写代码的日志信息。他突然发现自己没有记录这个 OJ 的 n n 究竟是多少。所幸他通过自己在 OJ 上的 Rank 知道了自动刷题机一共切了 k k 道题,希望你计算 n n 可能的最小值和最大值。 输入格式 第一行两个整数 l , k l,k,表示刷题机的日志一共有 l l 行,一共了切了 k k 题。 接下来 l l 行,每行一个整数 x i x i ​ ,依次表示每条日志。若 x i ≥ 0 x i ​ ≥0,则表示写了 x i x i ​ 行代码,若 x i < 0 x i ​ <0,则表示删除了 − x i −x i ​ 行代码。 输出格式 输出一行两个整数,分别表示 n n 可能的最小值和最大值。 如果这样的 n n 不存在,请输出一行一个整数 − 1 −1。c++
最新发布
11-22
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值