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. jq动画实现左右滑动

    <!DOCTYPE html> <html> <head> <title>jquery动画滑动</title> <style type ...

  2. Hadoop记录-metastore jmx配置

    参考:http://www.lixiuliang.cn/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/ 1.修改bin/hive文件 添加jvm启动参数: if [ $ ...

  3. JAVA发红包案例

    模拟拼手气红包* 对于指定总金额以及红包个数,可以生成不同金额的红包,*,每个红包金额随机生成. * 分析这个题目:* 1.首先需要一个分发红包的方法.输入的参数是 总金额 以及 红包个数.* 按照这 ...

  4. JDBC Template

    JDBC Template 1. Spring JDBC Spring框架对JDBC的简单封装,提供了一个JDBCTemplate对象用来简化JDBC的开发 步骤: 导入jar包 创建JDBCTemp ...

  5. pymysql的使用及sql注入

    pymysql简介 pymysql是python操纵mysql的一个模块,本质上是一个socket客户端 pymysql使用 准备数据 #创建数据库db2,如果已存在,请忽略 CREATE DATAB ...

  6. Select文字居右显示

    使用text-align: right;不起作用,应当使用direction: rtl;

  7. 调用腾讯、百度翻译API,实现游戏机翻通用程序

    最近玩了款steam独立游戏,没中文,只能自己汉化了,用腾讯跟百度的API实现了一个通用的机翻程序(只需要导入JSON文本), 同样,比较懒,还没写,先占坑

  8. 拍拍熊(APT-C-37),诱导方式、DNS、安卓远控

    诱导方式 1.含有正常APP功能的伪装 2.文件图标伪装 RAR 1.Android DroidJack SpyNote Windows njRAT njRAT[2]又称Bladabindi,通过控制 ...

  9. List的分组,求和,过滤操作

    package ---; import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; /* ...

  10. 关于git 远程仓库密码一直输错的问题

    解决方法, git 换地方使用后需要重新配置秘钥,一个钥匙开一个地方的门: 如果还不行, 在控制面板-用户账户-凭据管理-加添凭证,输入正确的账号密码:因为Windows的凭据管理器里面可能保存了你刚 ...