BZOJ.2823.[AHOI2012]信号塔(最小圆覆盖 随机增量法)
一个经典的随机增量法,具体可以看这里,只记一下大体流程。
一个定理:如果一个点\(p\)不在点集\(S\)的最小覆盖圆内,那么它一定在\(S\bigcup p\)的最小覆盖圆上。
所以假设我们有了前\(i-1\)个点的最小覆盖圆,那么只需要判断\(i\)在不在其内,就可以确定\(i\)是否在当前最小覆盖圆上。
算法流程:
- 设前\(i-1\)个点的最小覆盖圆是\(C\),判断第\(i\)个点是否在\(C\)内。如果是,则\(i\)个点的最小覆盖圆也是\(C\);否则进行\(2\)。
- 确定\(p_i\)为最小覆盖圆上的一个点。枚举点\(j\),判断\(j\)是否在当前最小覆盖圆内。如果是,跳过;否则确定\(p_j\)也是最小覆盖圆上的一个点,圆心为线段\((p_i,p_j)\)的中点,半径为\(\frac{dis(p_i,p_j)}{2}\),进行\(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]信号塔(最小圆覆盖 随机增量法)的更多相关文章
- bzoj 2823: [AHOI2012]信号塔 最小圆覆盖
题目大意: 给定n个点,求面积最小的园覆盖所有点.其中\(n \leq 10^6\) 题解: 恩... 刚拿到这道题的时候... 什么???最小圆覆盖不是\(O(n^3)\)的随机增量算法吗????? ...
- 【bzoj1336/1337/2823】[Balkan2002]Alien最小圆覆盖 随机增量法
题目描述 给出N个点,让你画一个最小的包含所有点的圆. 输入 先给出点的个数N,2<=N<=100000,再给出坐标Xi,Yi.(-10000.0<=xi,yi<=10000. ...
- 2018.07.04 BZOJ 2823: AHOI2012信号塔(最小圆覆盖)
2823: [AHOI2012]信号塔 Time Limit: 10 Sec Memory Limit: 128 MB Description 在野外训练中,为了确保每位参加集训的成员安全,实时的掌握 ...
- BZOJ 2823: [AHOI2012]信号塔
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2823 随机增量法.不断加点维护圆,主要是三点共圆那里打得烦(其实也就是个两中垂线求交点+联立方 ...
- 【BZOJ1336】[Balkan2002]Alien最小圆覆盖 随机增量法
[BZOJ1336][Balkan2002]Alien最小圆覆盖 Description 给出N个点,让你画一个最小的包含所有点的圆. Input 先给出点的个数N,2<=N<=10000 ...
- AHOI2012 信号塔 | 最小圆覆盖模板
题目链接:戳我 最小圆覆盖. 1.枚举第一个点,考虑当前圆是否包含了这个点,如果没有,则把圆变成以这个点为圆心,半径为0的圆. 2.枚举第二个点,考虑圆是否包含了这个点,如果没有,则把圆变成以这两个点 ...
- [BZOJ2823][BZOJ1336][BZOJ1337]最小圆覆盖(随机增量法)
算法介绍网上有很多,不解释了. 给出三点坐标求圆心方法:https://blog.csdn.net/liyuanbhu/article/details/52891868 记得先random_shuff ...
- hdu 3007【最小圆覆盖-随机增量法模板】
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> usin ...
- 【BZOJ】2823: [AHOI2012]信号塔
题意 给\(n\)个点,求一个能覆盖所有点的面积最小的圆.(\(n \le 50000\)) 分析 随机增量法 题解 理论上\(O(n^3)\)暴力,实际上加上随机化后期望是\(O(n)\)的. 算法 ...
随机推荐
- css样式关键字(initial,inherit,unset,revert,all)
关键字 在CSS中,有4个关键字理论上可以应用于任何的CSS属性,它们是initial(初始).inherit(继承).unset(未设置).revert(还原).而all的取值只能是以上这4个关键字 ...
- spring boot打包
1.application继承SpringBootServletInitializer 重写configure方法如下图 2.去掉项目中多余的main方法 3.将pom.xml打包改为war包 4. ...
- Shiro 系列: 简单命令行程序示例
在本示例中, 使用 INI 文件来定义用户和角色. 首先学习一下 INI 文件的规范. =======================Shiro INI 的基本规范================== ...
- kde钱包 忘记密码
转自 https://forum.suse.org.cn/t/kwallet/4367/2 修改 ~/.config/kwalletrc文件的First Use=false 改成 true 应该可以重 ...
- 菜鸟博客装饰分享CSS+HTML+js
博客布局更改,各种百度,自己修改,搞成现在这样,有兴趣的朋友可以复制我下面的把自己博客覆盖了,然后在进行更改 不懂可加群问我:675678830 如果想开通打赏,用到js,需要在 下列中 博客侧边栏公 ...
- 在visual studio 2013中编译Lua5.3.1
注:以下是基于 别人的教程或笔记来操作并按照自己的操作记录的纯文字版编译和hello lua过程. 原图文版链接: 原文链接 1.创建空的解决方案: 文件->新建->项目->其他项目 ...
- 【原创】大叔经验分享(1)在yarn上查看hive完整执行sql
hive执行sql提交到yarn上的任务名字是被处理过的,通常只能显示sql的前边一段和最后几个字符,这样就会带来一些问题: 1)相近时间提交了几个相近的sql,相互之间无法区分: 2)一个任务有问题 ...
- 【python】笔记
texts=[[word for word in document.lower().split() if word not in stoplist] for document in documents ...
- Flask开发微电影网站(九)
1.后台管理之电影管理 1.1 电影管理之所有电影收藏列表 1.1.1 电影管理之电影收藏列表视图函数 在admin目录下的views.py文件中定义电影收藏列表视图函数 电影收藏列表视图函数需要被登 ...
- git命令之git remote的用法
git remote git remote -v git init git add xxx git commit -m 'xxx' git remote add origin ssh://softw ...