【AHOI2012】【BZOJ2823】信号塔

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

HINT

1≤N≤500000

Source
裸的最小圆覆盖问题.随机增量法.
(这个东西的复杂度看起来好奇怪啊卧槽为什么是O(n)的!QAQ)
注意BZOJ不能用srand(time(0))

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<ctime>
#define eps 1e-6
#define MAXN 1000100
using namespace std;
int n;
double r;
struct point
{
    double x,y;
}s[MAXN],C;
double sqr(double x)
{
    return x*x;
}
double dis(point a,point b)
{
    return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
}
point cen(point a,point b,point c)//已知三点求圆心 
{
    double x,y;
    double ax=sqr(a.x),ay=sqr(a.y),bx=sqr(b.x),by=sqr(b.y),cx=sqr(c.x),cy=sqr(c.y);
    double l1=ax-bx+ay-by,l2=ax-cx+ay-cy;
    double r1=2*a.x-2*b.x,r2=2*a.y-2*b.y,r3=2*a.x-2*c.x,r4=2*a.y-2*c.y;
    x=(l1-r2/r4*l2)/(r1-r2/r4*r3);y=(l1-r1/r3*l2)/(r2-r1/r3*r4);
    if (r4==0)  x=(a.x+c.x)/2;
    if (r3==0)  y=(a.y+c.y)/2;
    return (point){x,y};
}
point Mid(point a,point b)
{
    return (point){(a.x+b.x)/2,(a.y+b.y)/2};
}
int main()
{
    //srand(time(0));
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%lf%lf",&s[i].x,&s[i].y);
        //swap(s[i],s[(rand()|rand()<<16)%i+1]);
        swap(s[i],s[rand()%i+1]);
    }
    C=s[1];
    for (int i=1;i<=n;i++)//为什么这种东西的时间复杂度会有保证QwQ 
    {
        if (dis(C,s[i])<=r+eps) continue;
        C=Mid(s[1],s[i]);r=dis(s[i],C);
        for (int j=1;j<i;j++)
        {
            if (dis(C,s[j])<=r+eps) continue;
            C=Mid(s[i],s[j]);r=dis(s[i],C);
            for (int k=1;k<j;k++)
            {
                if (dis(C,s[k])<=r+eps) continue;
                C=cen(s[i],s[j],s[k]);r=dis(s[i],C);
            }
        }
    }
    printf("%.2lf %.2lf %.2lf\n",C.x,C.y,r);
}

你可能感兴趣的:(计算几何,最小圆覆盖)