洛谷 P1742 最小圆覆盖 (随机增量)
题目链接:P1742 最小圆覆盖
题意
给出 N 个点,求最小的包含所有点的圆。
思路
随机增量
最小圆覆盖一般有两种做法:随机增量和模拟退火。随机增量的精确度更高,这里介绍随机增量的做法。
先将所有点随机打乱。
令前 \(i - 1\) 个点的最小覆盖圆为圆 \(O\),加入第 \(i\) 个点。
如果第 \(i\) 个点在圆 \(O\) 内或圆 \(O\) 上,则前 \(i\) 个点的最小覆盖圆还是圆 \(O\)。
否则新得到的最小覆盖圆肯定经过第 \(i\) 个点。然后确定前 \(i − 1\) 个点中还有哪两个点在最小覆盖圆上。
以第 \(i\) 个点为圆心,半径为 \(0\),重复以上过程依次加入点 \(P_j\)。(圆心为 \(\frac{P_i+P_j}{2}\),半径为 \(\frac{|P_iP_j|}{2}\))
固定两个点之后再重复以上步骤找第三个点。(因为需要三个点来确定一个圆)
遍历完所有点之后,所得到的圆就是最小覆盖圆。
时间复杂度为 \(O(n)\)
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const db eps = 1e-8;
const db pi = acos(-1.0);
const ll maxn = 1e5 + 10;
inline int dcmp(db x) {
if(fabs(x) < eps) return 0;
return x > 0? 1: -1;
}
class Point {
public:
double x, y;
Point(double x = 0, double y = 0) : x(x), y(y) {}
void input() {
scanf("%lf%lf", &x, &y);
}
bool operator<(const Point &a) const {
return (!dcmp(x - a.x))? dcmp(y - a.y) < 0: x < a.x;
}
bool operator==(const Point &a) const {
return dcmp(x - a.x) == 0 && dcmp(y - a.y) == 0;
}
db dis2(const Point a) {
return pow(x - a.x, 2) + pow(y - a.y, 2);
}
db dis(const Point a) {
return sqrt(dis2(a));
}
db dis2() {
return x * x + y * y;
}
db dis() {
return sqrt(dis2());
}
Point operator+(const Point a) {
return Point(x + a.x, y + a.y);
}
Point operator-(const Point a) {
return Point(x - a.x, y - a.y);
}
Point operator*(double p) {
return Point(x * p, y * p);
}
Point operator/(double p) {
return Point(x / p, y / p);
}
db dot(const Point a) {
return x * a.x + y * a.y;
}
db cross(const Point a) {
return x * a.y - y * a.x;
}
db ang(Point a) {
return acos((a.dis() * dis()) / dot(a));
}
};
typedef Point Vector;
class Circle {
public:
Point o;
db r;
Circle() {}
Circle(Point o, db r):o(o), r(r){}
// 三点定圆
Circle(Point A, Point B, Point C) {
double a1 = B.x - A.x, b1 = B.y - A.y, c1 = (a1 * a1 + b1 * b1) / 2;
double a2 = C.x - A.x, b2 = C.y - A.y, c2 = (a2 * a2 + b2 * b2) / 2;
double d = a1 * b2 - a2 * b1;
o.x = A.x + (c1 * b2 - c2 * b1) / d;
o.y = A.y + (a1 * c2 - a2 * c1) / d;
r = o.dis(A);
}
Point point(db a) {
return Point(o.x + cos(a) * r, o.y + sin(a) * r);
}
// 点在圆内
bool PinC(Point p) {
db d = p.dis(o);
return dcmp(d - r) < 0;
}
// 点在圆外
bool PoutC(Point p) {
db d = p.dis(o);
return dcmp(d - r) > 0;
}
};
vector<Point> p;
// 最小圆覆盖
Circle min_circle(vector<Point> p) {
int sz = p.size();
random_shuffle(p.begin(), p.end());
Circle ans(p[0], 0.0);
for(int i = 0; i < sz; ++i) {
if(ans.PoutC(p[i])) {
ans = Circle(p[i], 0);
for(int j = 0; j < i; ++j) {
if(ans.PoutC(p[j])) {
ans = Circle((p[i] + p[j]) / 2.0, p[i].dis(p[j]) / 2.0);
for(int k = 0; k < j; ++k) {
if(ans.PoutC(p[k])) {
ans = Circle(p[i], p[j], p[k]);
}
}
}
}
}
}
return ans;
}
int main() {
int n;
scanf("%d", &n);
for(int i = 0; i < n; ++i) {
Point tmp;
tmp.input();
p.push_back(tmp);
}
Circle ans = min_circle(p);
printf("%.10lf\n%.10lf %.10lf\n", ans.r, ans.o.x, ans.o.y);
return 0;
}
参考
洛谷 P1742 最小圆覆盖 (随机增量)的更多相关文章
- (bzoj1337 || 洛谷P1742 最小圆覆盖 )|| (bzoj2823 || 洛谷P2533 [AHOI2012]信号塔)
bzoj1337 洛谷P1742 用随机增量法.讲解:https://blog.csdn.net/jokerwyt/article/details/79221345 设点集A的最小覆盖圆为g(A) 可 ...
- 洛谷P1742 最小圆覆盖(计算几何)
题面 传送门 题解 之前只是在抄题解--这篇才算是真正自己想的吧-- 首先我们把输入序列给\(random\)一下防止出题人好心送你一个毒瘤序列 我们设\(r\)为当前最大半径,\(o\)为此时对应圆 ...
- 洛谷P1742 最小圆覆盖(计算几何)
题意 题目链接 Sol 暴力做法是\(O(n^3)\)枚举三个点然后check一下是否能包含所有点 考虑一种随机算法,首先把序列random_shuffle一下. 然后我们枚举一个点\(i\),并维护 ...
- BZOJ.2823.[AHOI2012]信号塔(最小圆覆盖 随机增量法)
BZOJ 洛谷 一个经典的随机增量法,具体可以看这里,只记一下大体流程. 一个定理:如果一个点\(p\)不在点集\(S\)的最小覆盖圆内,那么它一定在\(S\bigcup p\)的最小覆盖圆上. 所以 ...
- 【bzoj1336/1337/2823】[Balkan2002]Alien最小圆覆盖 随机增量法
题目描述 给出N个点,让你画一个最小的包含所有点的圆. 输入 先给出点的个数N,2<=N<=100000,再给出坐标Xi,Yi.(-10000.0<=xi,yi<=10000. ...
- 【BZOJ1336】[Balkan2002]Alien最小圆覆盖 随机增量法
[BZOJ1336][Balkan2002]Alien最小圆覆盖 Description 给出N个点,让你画一个最小的包含所有点的圆. Input 先给出点的个数N,2<=N<=10000 ...
- [BZOJ2823][BZOJ1336][BZOJ1337]最小圆覆盖(随机增量法)
算法介绍网上有很多,不解释了. 给出三点坐标求圆心方法:https://blog.csdn.net/liyuanbhu/article/details/52891868 记得先random_shuff ...
- hdu 3007【最小圆覆盖-随机增量法模板】
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> usin ...
- 最小圆覆盖(洛谷 P1742 增量法)
题意:给定N个点,求最小圆覆盖的圆心喝半径.保留10位小数点. N<1e5: 思路:因为精度要求较高,而且N比较大,所以三分套三分的复杂度耶比较高,而且容易出错. 然是写下增量法吧. 伪代码加深 ...
随机推荐
- LeetCode 最短无序连续子数组
题目链接:https://leetcode-cn.com/problems/shortest-unsorted-continuous-subarray/ 题目大意: 略. 分析: 如果排序区间为 [L ...
- 深入理解__proto__ 、constructor和prototype的关系
深入理解__proto__ .constructor和prototype的关系 2013-11-12 09:56 1390人阅读 评论(3) 收藏 举报 分类: 前端之Javascript(59) ...
- SourceTree 这是一个无效源路径/URL的 解决方法
看网上的教程都解决不了,这是一个大坑,折腾了很久. 如果说你的项目存在,而不是url真的无效,那就是因为你的权限问题. 因为你的sourcetree登过其他账号,在sourceTree设置里面记录了他 ...
- 拓展练习--find查找、打包压缩、服务器、磁盘挂载
目录 find查找.打包压缩 服务器部分 磁盘挂载及单用户模式 find查找.打包压缩 1.超级用户(管理员用户)提示符是_#,普通用户提示符是$_. 2.如何快速返回上一次所在的目录? cd - 3 ...
- opengl 库glew
OpenGL OpenGL是个专业的3D程序接口,是一个功能强大,调用方便的底层3D图形库.OpenGL的前身是SGI公司为其图形工作站开发的IRIS GL.IRIS GL是一个工业标准的3D图形软件 ...
- [HTML知识体系]语义化标签概论
1.什么是语义化 语义化(Semantic)在HTML5中被大量提起,就是语义化标签向浏览器和开发者展示了它所包裹内容的类型与意思,可是至今我看了好多代码,HTML5新增的语义化标签的使用率还是挺低的 ...
- 力扣 -- 寻找两个有序数组的中位数 Median of Two Sorted Arrays python实现
题目描述: 中文: 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2. 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n)). 你可以假设 nums ...
- 74th Jupyter Notebook 插入图片的方法
转载: https://account.cnblogs.com/signin?ReturnUrl=http%3A%2F%2Fhome.cnblogs.com%2Fu%2Ferdou%2F 插入本地 ...
- 在 Visual Studio 中使用 Q# 进行量子编程
1 量子计算机与量子编程 1.1 量子计算机 Quantum computing is computing using quantum-mechanical phenomena, such as su ...
- 【串线篇】SpringMvc数据传出
/** * SpringMVC除过在方法上传入原生的request和session外还能怎么样把数据带给页面 * * 四大域: * pageContext:${pageScope.msg }< ...