洛谷 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比较大,所以三分套三分的复杂度耶比较高,而且容易出错. 然是写下增量法吧. 伪代码加深 ...
随机推荐
- 取余运算 C和python的区别
今天看书发现python与C的负数取余运算结果不同,查资料理解. 取余运算的算法是相同的 r = a- n*(a/n) n!=0 r是余数,a是被除数,n是除数.n不能为0,否则都会报错. 负数 ...
- CF1241 D Sequence Sorting(离散化+DP)
题意: 给定数组a[n],用两种操作: 1.将数组中所有值为x的数移至开头 2.将数组中所有值为x的数移至末尾 问,经过最少多少次操作,能将数组a[n]变为非递减的有序数列? (1<=n< ...
- Linux下docker安装教程
目前最新版本的docker19.03支持nvidia显卡与容器的无缝对接,从而摆脱了对nvidia-docker的依赖.因此毫不犹豫安装19.03版本的docker,安装教程可参考官方教程Centos ...
- 比较CGI,FastCGI,PHP-CGI与PHP-FPM的区别
最早的Web服务器,可以简单地响应浏览器发来的HTTP请求,并将存储在服务器上的HTML文件返回给浏览器,也就是静态html. 随着时间的变化,网站也越来越复杂,所以出现动态技术.但是服务器并不能直接 ...
- Python的基本数据类型,用户交互
整数: int 常见的数字都是int类型. 用于计算或者大小的比较 在32位机器上int的范围是: -2**31-2**31-1,即-2147483648-2147483647 在64位机器上int的 ...
- docker--数据持久化之Data Volume
使用mysql为例 查看docker hub官方的mysql image 的dockerfile,有这一行:VOLUME /var/lib/mysql -v给volume创建别名 [root@loca ...
- document.location window.location
document.location 和 window.location 取url的值的时候可以通用,但是 document是window的属性,所以不能直接用document.location =ur ...
- 2018-2-13-win10-UWP-单元测试
title author date CreateTime categories win10 UWP 单元测试 lindexi 2018-2-13 17:23:3 +0800 2018-2-13 17: ...
- JavaScript常用技巧之进制转换
一.十进制转二进制 (8).toString(2) 二.二进制转十进制 parseInt("1000",2) 三.获取当前时间戳 // 方法 Date.now() // 对象和操作 ...
- ASN.1
ASN.1抽象语法标记(Abstract Syntax Notation One https://baike.baidu.com/item/ASN.1/498523?fr=aladdin