BZOJ

洛谷


一个经典的随机增量法,具体可以看这里,只记一下大体流程。

一个定理:如果一个点\(p\)不在点集\(S\)的最小覆盖圆内,那么它一定在\(S\bigcup p\)的最小覆盖圆上。

所以假设我们有了前\(i-1\)个点的最小覆盖圆,那么只需要判断\(i\)在不在其内,就可以确定\(i\)是否在当前最小覆盖圆上。

算法流程:

  1. 设前\(i-1\)个点的最小覆盖圆是\(C\),判断第\(i\)个点是否在\(C\)内。如果是,则\(i\)个点的最小覆盖圆也是\(C\);否则进行\(2\)。
  2. 确定\(p_i\)为最小覆盖圆上的一个点。枚举点\(j\),判断\(j\)是否在当前最小覆盖圆内。如果是,跳过;否则确定\(p_j\)也是最小覆盖圆上的一个点,圆心为线段\((p_i,p_j)\)的中点,半径为\(\frac{dis(p_i,p_j)}{2}\),进行\(3\)。
  3. 枚举点\(k\),判断\(k\)是否在当前最小覆盖圆内。如果是,跳过;否则确定当前最小覆盖圆为\((p_i,p_j,p_k)\)的外接圆。

算法的复杂度分析:(随机数据下,)因为只需要确定三个点,\(n\)个点中每个点在圆上的概率是\(\frac3n\)。

那么第一层循环的复杂度\(T_1(n)=O(n)+\sum_{i=1}^nT_2(i)\),第二层循环复杂度\(T_2(n)=O(n)+\sum_{i=1}^nT_3(i)\),第三次循环复杂度为\(T_3(n)=O(n)\)。

化简一下就可以得出算法的均摊复杂度为\(O(n)\)。

注意要保证点的顺序是随机的。

具体细节:

如何求三个点\((p_i,p_j,p_k)\)的最小覆盖圆:

就是用一个性质。。垂直平分线(中垂线)上的点到线段两边点的距离相同。那么求出两条线段的垂直平分线,求个交点就行了。

垂直平分线的求法就是先求一个中点(坐标相加除以\(2\)),然后做垂线(将另一个两点之间的向量旋转\(90^{\circ}\))。


//16952kb	780ms
#include <cmath>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define MAXIN 500000
//#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=1e6+5; char IN[MAXIN],*SS=IN,*TT=IN;
struct Vec
{
double x,y;
Vec(double x=0,double y=0):x(x),y(y) {}
Vec operator +(const Vec &a)const {return Vec(x+a.x, y+a.y);}
Vec operator -(const Vec &a)const {return Vec(x-a.x, y-a.y);}
Vec operator *(const double a)const {return Vec(x*a, y*a);}
double operator *(const Vec &a)const {return x*a.y-y*a.x;}
Vec Rotate_90()const {return Vec(y,-x);}
double len()const {return sqrt(x*x+y*y);}
double len2()const {return x*x+y*y;}
}p[N];
typedef Vec Point;
struct Line
{
Point p; Vec v;
Line(Point p,Vec v):p(p),v(v) {}
Line PerpendicularBisector()const//垂直平分线=-=
{
return Line((p+p+v)*0.5,v.Rotate_90());
}
Point Intersection(const Line &l)const
{
return p+v*((l.v*(p-l.p))/(v*l.v));
}
}; inline double read()
{
double x=0,y=0.1,f=1;register char c=gc();
for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
for(;isdigit(c);x=x*10+c-48,c=gc());
for(c=='.'&&(c=gc());isdigit(c);x+=y*(c-48),y*=0.1,c=gc());
return x*f;
}
Point CalcCircle(const Point &a,const Point &b,const Point &c)
{
// Line A=Line(a,b-a).PerpendicularBisector(),B=Line(a,c-a).PerpendicularBisector();
Line A=Line((a+b)*0.5,(b-a).Rotate_90()),B=Line((a+c)*0.5,(c-a).Rotate_90());
return A.Intersection(B);
}
void Solve(const int n)
{
srand(330), std::random_shuffle(p+1,p+1+n);//话说这个srand不够随机啊= =
Point O=p[1]; double R=0;
for(int i=2; i<=n; ++i)
if((p[i]-O).len2()>R)
{
O=p[i], R=0;
for(int j=1; j<i; ++j)
if((p[j]-O).len2()>R)
{
O=(p[i]+p[j])*0.5, R=(p[i]-O).len2();
for(int k=1; k<j; ++k)
if((p[k]-O).len2()>R)
O=CalcCircle(p[i],p[j],p[k]), R=(p[k]-O).len2();
}
}
printf("%.2f %.2f %.2f\n",O.x,O.y,sqrt(R));
} int main()
{
int n=read();
for(int i=1; i<=n; ++i) p[i].x=read(),p[i].y=read();
// for(int i=1; i<=n; ++i) p[i]=(Point){read(),read()};//声明构造函数之后再这么用,貌似。。= = 不同编译器结果不同。。
Solve(n); return 0;
}

BZOJ.2823.[AHOI2012]信号塔(最小圆覆盖 随机增量法)的更多相关文章

  1. bzoj 2823: [AHOI2012]信号塔 最小圆覆盖

    题目大意: 给定n个点,求面积最小的园覆盖所有点.其中\(n \leq 10^6\) 题解: 恩... 刚拿到这道题的时候... 什么???最小圆覆盖不是\(O(n^3)\)的随机增量算法吗????? ...

  2. 【bzoj1336/1337/2823】[Balkan2002]Alien最小圆覆盖 随机增量法

    题目描述 给出N个点,让你画一个最小的包含所有点的圆. 输入 先给出点的个数N,2<=N<=100000,再给出坐标Xi,Yi.(-10000.0<=xi,yi<=10000. ...

  3. 2018.07.04 BZOJ 2823: AHOI2012信号塔(最小圆覆盖)

    2823: [AHOI2012]信号塔 Time Limit: 10 Sec Memory Limit: 128 MB Description 在野外训练中,为了确保每位参加集训的成员安全,实时的掌握 ...

  4. BZOJ 2823: [AHOI2012]信号塔

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2823 随机增量法.不断加点维护圆,主要是三点共圆那里打得烦(其实也就是个两中垂线求交点+联立方 ...

  5. 【BZOJ1336】[Balkan2002]Alien最小圆覆盖 随机增量法

    [BZOJ1336][Balkan2002]Alien最小圆覆盖 Description 给出N个点,让你画一个最小的包含所有点的圆. Input 先给出点的个数N,2<=N<=10000 ...

  6. AHOI2012 信号塔 | 最小圆覆盖模板

    题目链接:戳我 最小圆覆盖. 1.枚举第一个点,考虑当前圆是否包含了这个点,如果没有,则把圆变成以这个点为圆心,半径为0的圆. 2.枚举第二个点,考虑圆是否包含了这个点,如果没有,则把圆变成以这两个点 ...

  7. [BZOJ2823][BZOJ1336][BZOJ1337]最小圆覆盖(随机增量法)

    算法介绍网上有很多,不解释了. 给出三点坐标求圆心方法:https://blog.csdn.net/liyuanbhu/article/details/52891868 记得先random_shuff ...

  8. hdu 3007【最小圆覆盖-随机增量法模板】

    #include<iostream> #include<cstdio> #include<cmath> #include<algorithm> usin ...

  9. 【BZOJ】2823: [AHOI2012]信号塔

    题意 给\(n\)个点,求一个能覆盖所有点的面积最小的圆.(\(n \le 50000\)) 分析 随机增量法 题解 理论上\(O(n^3)\)暴力,实际上加上随机化后期望是\(O(n)\)的. 算法 ...

随机推荐

  1. MacBook 整个配置过程,供新入手MacBook的同学

    这里记录了MacBook 的整个配置过程,可供新入手MacBook和觉得MacBook比较难用的同学参考. 1. 外围拓展 笔记本电脑的特点是携带方便,缺点是屏幕太小,因此你首先需要再申请领用一个外接 ...

  2. js重点--闭包

    闭包: 1.获取到局部变量,相当于是函数局部与外部的桥梁 2.使局部变量保存在内存中,不被回收 <script> function outerFn() { var outerVar = 0 ...

  3. Docker:私有仓库registry [十一]

    一.运行docker私有仓库 安装registry docker run -d -p 5000:5000 --restart=always --name registry -v /opt/myregi ...

  4. MapReduce-FileInputFormat

    在运行 MapReduce 程序时,输入的文件格式包括:基于行的日志文件.二进制格式文件.数据库表等.那么,针对不同的数据类型,MapReduce 是如何读取这些数据? FileInputFormat ...

  5. idea设置java内存

    -Xms1024m -Xmx10240m -XX:MaxPermSize=512m 设置环境变量JAVA_OPTS="-server -Xms800m -Xmx800m -XX:PermSi ...

  6. MongoDB 分片集群技术

    在了解分片集群之前,务必要先了解复制集技术! 1.1 MongoDB复制集简介 一组Mongodb复制集,就是一组mongod进程,这些进程维护同一个数据集合.复制集提供了数据冗余和高等级的可靠性,这 ...

  7. [译]Ocelot - Delegating Handlers

    原文 可以为HttpClient添加delegating handlers. Usage 为了添加delegating handler需要做两件事. 首先如下一样创建一个类. public class ...

  8. iPhone8再MacOS上修改手机铃声

    1 选择下载好的mp3铃声文件,导入到itunes 2 将音乐改成AAA模式, 设置你的铃声时长 3 show in finder 找到文件,将mpr后缀修改成m4r,并删除掉mp3文件,将m4r文件 ...

  9. 边缘检测之Canny

    1. 写在前面 最近在做边缘检测方面的一些工作,在网络上也找了很多有用的资料,感谢那些积极分享知识的先辈们,自己在理解Canny边缘检测算法的过程中也走了一些弯路,在编程实现的过程中,也遇到了一个让我 ...

  10. pytorch multi-gpu train

    记录一下pytorch如何进行单机多卡训练: 官网例程:https://pytorch.org/tutorials/beginner/blitz/data_parallel_tutorial.html ...