共N+1行,第一行为正整数N(1≤N≤1000000),表示队员个数。接下来
N行,每行两个实数用空格分开,分别是第i个队员的坐标X
一行,共三个实数(中间用空格隔开),分别是信号塔的坐标,和信号塔 覆盖的半径。 (注:队员是否在边界上的判断应符合他到圆心的距离与信号塔接收半径之差的绝对值小于10^-6
1≤N≤500000
随机增量法求最小圆覆盖。
三倍经验题~
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#define eps 1e-12
using namespace std;
int n;
double r;
struct Point
{
double x,y;
friend Point operator + (Point a,Point b)
{
return (Point){a.x+b.x,a.y+b.y};
}
friend Point operator - (Point a,Point b)
{
return (Point){a.x-b.x,a.y-b.y};
}
friend Point operator / (Point a,double p)
{
return (Point){a.x/p,a.y/p};
}
}p[500005],o;
double dis(Point a,Point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
Point rev(Point x)
{
return (Point){-x.y,x.x};
}
Point Geto(Point a,Point b,Point c)
{
Point x1=(a+b)/2,x2=(a+b)/2+rev(a-b),y1=(a+c)/2,y2=(a+c)/2+rev(a-c);
if (fabs(y1.x-y2.x)<eps)
swap(x1,y1),swap(x2,y2);
double k2=(y1.y-y2.y)/(y1.x-y2.x),b2=y2.y-y2.x*k2;
if (fabs(x1.x-x2.x)<eps)
return (Point){x1.x,k2*x1.x+b2};
double k1=(x1.y-x2.y)/(x1.x-x2.x),b1=x2.y-k1*x2.x;
double x=(b2-b1)/(k1-k2);
return (Point){x,x*k1+b1};
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
for (int i=1;i<=n;i++)
swap(p[rand()%n+1],p[rand()%n+1]);
o=p[1],r=0.0;
for (int i=2;i<=n;i++)
{
if (dis(o,p[i])<r+eps) continue;
o=(p[i]+p[1])/2,r=dis(p[1],o);
for (int j=2;j<i;j++)
{
if (dis(o,p[j])<r+eps) continue;
o=(p[i]+p[j])/2,r=dis(p[i],o);
for (int k=1;k<j;k++)
{
if (dis(o,p[k])<r+eps) continue;
o=Geto(p[i],p[j],p[k]);
r=dis(p[i],o);
}
}
}
printf("%.2lf %.2lf %.2lf\n",o.x,o.y,r);
return 0;
}
原文地址:http://blog.csdn.net/regina8023/article/details/44861077