[BZOJ2823][AHOI2012]信号塔

[AHOI2012]信号塔

Description
在野外训练中,为了确保每位参加集训的成员安全,实时的掌握和收集周边环境和队员信息非常重要,集训队采用的方式是在训练所在地散布N个小型传感器来收集并传递信息,这些传感器只与设在集训地中的信号塔进行通信,信号塔接收信号的覆盖范围是圆形,可以接收到所有分布在该集训区域内所有N个小型传感器(包括在该圆形的边上)发出的信号。信号塔的功率与信号塔接收范围半径的大小成正比,因为是野外训练,只能使用事先储备好的蓄电设备,因此在可以收集所有传感器信息的基础上,还应使得信号塔的功率最小。小龙帮助教官确定了一种信号塔设置的方案,既可以收集到所有N个传感器的信号,又可以保证这个信号塔的功率是最小的。同学们,你们知道,这个信号塔的信号收集半径有多大,它应该设置在何处吗?
Input
共N+1行,第一行为正整数N(1≤N≤1000000),表示队员个数。接下来
N行,每行两个实数用空格分开,分别是第i个队员的坐标X
Output
一行,共三个实数(中间用空格隔开),分别是信号塔的坐标,和信号塔 覆盖的半径。 (注:队员是否在边界上的判断应符合他到圆心的距离与信号塔接收半径之差的绝对值小于10^-6
Sample Input
5
1.200 1.200
2.400 2.400
3.800 4.500
2.500 3.100
3.900 1.300
Sample Output
2.50 2.85 2.10

Solution
经典模型:最小圆覆盖,用最小的圆覆盖住平面上的 n <script type="math/tex" id="MathJax-Element-2531">n</script>个点
可以看这里:http://blog.sina.com.cn/s/blog_6e63f59e010120dl.html

Code

#include <bits/stdc++.h>

using namespace std;

const double eps = 1e-6;
const int N = 1000000+10;

#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define MS(_) memset(_, 0, sizeof(_))
#define MP make_pair
#define PB push_back
#define debug(...) fprintf(stderr, __VA_ARGS__)

struct Vec{
    double x, y;
    Vec() {}
    Vec(double _x, double _y) : x(_x), y(_y) {}
    inline double len() const{return sqrt(x*x+y*y);}
};
inline Vec operator + (const Vec &a, const Vec &b){return Vec(a.x+b.x,a.y+b.y);}
inline Vec operator - (const Vec &a, const Vec &b){return Vec(a.x-b.x,a.y-b.y);}
template<typename T> inline Vec operator * (const Vec &a, T b){return Vec(a.x*b,a.y*b);}
template<typename T> inline Vec operator * (T a, const Vec &b){return Vec(a*b.x,a*b.y);}
template<typename T> inline Vec operator / (const Vec &a, T b){return Vec(a.x/b,a.y/b);}
inline double dot (const Vec &a, const Vec &b){return a.x*b.x+a.y*b.y;}
inline double cross (const Vec &a, const Vec &b){return a.x*b.y-a.y*b.x;}
typedef Vec Poi;
inline bool gt(double x, double y) {return x-y>eps;}
inline bool eq0(double x) {return abs(x)<=eps;}
inline bool lt0(double x) {return x<-eps;}

int n;
Poi p[N], O;
double r;

inline double sqr(double x) {return x*x;}
inline Poi solve(Poi a, Poi b, Poi c){
    Poi A = 2*Vec(b.x-a.x, c.x-b.x);
    Poi B = 2*Vec(b.y-a.y, c.y-b.y);
    Poi C = Vec(sqr(b.len())-sqr(a.len()), sqr(c.len())-sqr(b.len()));
    double x = cross(C, B), y = cross(C, A), M = cross(A, B);
    return Vec(x,-y)/M;
}
int main(){
    scanf("%d", &n);
    rep(i, 1, n) scanf("%lf%lf", &p[i].x, &p[i].y);
    O = p[1]; r = 0;
    rep(i, 2, n) if (gt((p[i]-O).len(), r)){
        O = p[i]; r = 0;
        rep(j, 1, i-1) if (gt((p[j]-O).len(), r)){
            O = (p[i]+p[j])/2; r = (p[j]-O).len();
            rep(k, 1, j-1) if (gt((p[k]-O).len(), r)){
                Poi a = p[i], b = p[j], c = p[k];
                if (eq0(cross(b-a, c-b))){
                    if (lt0(dot(c-a, b-a))) a = c;
                    else if(lt0(dot(c-b, a-b))) b = c;
                    O = (a+b)/2; r = (O-a).len();
                }else{ O = solve(a, b, c); r = (O-a).len(); }
            }
        }
    }
    printf("%.2lf %.2lf %.2lf\n", O.x, O.y, r);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值