列表

详情


NC20534. [AHOI2012]信号塔

描述

在野外训练中,为了确保每位参加集训的成员安全,实时的掌握和收集周边环境和队员信息非常重要,集训队采用 的方式是在训练所在地散布N个小型传感器来收集并传递信息,这些传感器只与设在集训地中的信号塔进行通信, 信号塔接收信号的覆盖范围是圆形,可以接收到所有分布在该集训区域内所有N个小型传感器(包括在该圆形的边 上)发出的信号。
信号塔的功率与信号塔接收范围半径的大小成正比,因为是野外训练,只能使用事先储备好的蓄 电设备,因此在可以收集所有传感器信息的基础上,还应使得信号塔的功率最小。小龙帮助教官确定了一种信号塔 设置的方案,既可以收集到所有N个传感器的信号,又可以保证这个信号塔的功率是最小的。同学们,你们知道, 这个信号塔的信号收集半径有多大,它应该设置在何处吗?

输入描述

共N+1行,第一行为正整数N(1 ≤ N ≤ 1000000),表示队员个数。
接下来N行,每行两个实数用空格分开,分别是第i个队员的坐标X

输出描述

一行,共三个实数(中间用空格隔开),分别是信号塔的坐标,和信号塔覆盖的半径。(注:队员是否在边界上的判断应符合他到圆心的距离与信号塔接收半径之差的绝对值小于10^-6)

示例1

输入:

5 
1.200 1.200 
2.400 2.400 
3.800 4.500 
2.500 3.100 
3.900 1.300

输出:

2.50 2.85 2.10

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 275ms, 内存消耗: 8100K, 提交时间: 2020-10-05 19:19:16

#include<bits/stdc++.h>
#define eps 1e-6
using namespace std;

const int maxn=1e6+10;
struct node{
    double x,y;
}p[maxn],o;

double dis(node x,node y)
{
    return sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));
}

node circle(node a,node b,node c)//三点共圆圆心公式
{
    double X=( (a.x*a.x-b.x*b.x+a.y*a.y-b.y*b.y)*(a.y-c.y)-(a.x*a.x-c.x*c.x+a.y*a.y-c.y*c.y)*(a.y-b.y) ) / (2*(a.y-c.y)*(a.x-b.x)-2*(a.y-b.y)*(a.x-c.x));
    double Y=( (a.x*a.x-b.x*b.x+a.y*a.y-b.y*b.y)*(a.x-c.x)-(a.x*a.x-c.x*c.x+a.y*a.y-c.y*c.y)*(a.x-b.x) ) / (2*(a.y-b.y)*(a.x-c.x)-2*(a.y-c.y)*(a.x-b.x));
    double R=sqrt((X-a.x)*(X-a.x)+(Y-a.y)*(Y-a.y));
    return (node){X,Y};
}

double r=0;

void minicircle(int n)
{
    o=p[0],r=0;
    for(int i=0;i<n;i++){
        if(dis(p[i],o)-r>eps){
            o=p[i];r=0;
            for(int j=0;j<i;j++){
                if(dis(p[j],o)-r>eps){
                    o={(p[i].x+p[j].x)/2.0,(p[i].y+p[j].y)/2.0};
                    r=dis(p[i],p[j])/2.0;
                    for(int k=0;k<j;k++){
                        if(dis(p[k],o)-r>eps){
                            o=circle(p[i],p[j],p[k]);
                            r=dis(p[i],o);
                        }
                    }
                }
            }
        }
    }
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++) scanf("%lf%lf",&p[i].x,&p[i].y);
    srand((unsigned long)time(NULL));
    random_shuffle(p,p+n);
    minicircle(n);
    printf("%.2f %.2f %.2f\n",o.x,o.y,r);
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 257ms, 内存消耗: 8132K, 提交时间: 2020-10-16 20:07:20

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define ll long long
#define f(i,a,b) for(int i=a;i<=b;i++)
#define inf 0x7f7f7f7f;
const double eps=1e-5;
struct dot{
	double x,y;
}p[1000010],ans;
ll n;
double ar;
double dis(dot a,dot b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
dot Ce(dot p1,dot p2,dot p3){
    double a,b,c,d,e,f;
    a=p2.y-p1.y;
    b=p3.y-p1.y;
    c=p2.x-p1.x;
    d=p3.x-p1.x;
    f=p3.x*p3.x+p3.y*p3.y-p1.x*p1.x-p1.y*p1.y;
    e=p2.x*p2.x+p2.y*p2.y-p1.x*p1.x-p1.y*p1.y;
    return (dot){(a*f-b*e)/(2*a*d-2*b*c),(d*e-c*f)/(2*a*d-2*b*c)};
}
int main(){
	
	scanf("%lld",&n);
	f(i,1,n)scanf("%lf%lf",&p[i].x,&p[i].y);
	//cout<<Ce(p[1],p[2],p[3]).x;
	//random_shuffle(p+1,p+n+1);
	ar=dis(p[1],p[2])/2.0,ans=(dot){(p[1].x+p[2].x)/2.0,(p[1].y+p[2].y)/2.0};
	f(i,2,n)
		if(dis(p[i],ans)>ar+eps){
			ans=p[i],ar=0;
			f(j,1,i-1)
				if(dis(p[j],ans)>ar+eps){
					ans=(dot){(p[i].x+p[j].x)/2.0,(p[i].y+p[j].y)/2.0};
					ar=dis(ans,p[i]);
					f(k,1,j-1)if(dis(p[k],ans)>ar+eps)ans=Ce(p[i],p[j],p[k]),ar=dis(ans,p[i]);
				}
		}
	printf("%.2lf %.2lf %.2lf",ans.x,ans.y,ar);
	return 0;
}

上一题