题目

给出 $N(1 \leq N \leq 100)$ 个点的坐标 $x_i,y_i,z_i$($-100000 \leq x_i,y_i,z_i \leq 100000$),求包围全部点的最小的球。

2018南京区域赛D题

分析

方法一:模拟退火

模拟退火是 解决最小球覆盖的经典方法,效果也非常好。

随机得到球的中心,如果更小的半径或设定的概率,则转移。(详细解释见链接

//这个代码严格说不是模拟退火

有一个事实:最小球的球心,它不然是一个确定的点,就是距它最远的4个点且等距

于是,我们任选一个点作为初始球心,再在点集中找到距它最远的点,我们让球心靠近最远的点,同时使步长逐渐变小,不断重复此过程,就可以让球心到达正确的位置

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <cmath>
#include <set>
#define LL long long
using namespace std;
const int MAXN = ;
const double eps = 1e-;
struct Point
{
double x, y, z;
Point(double x = , double y = , double z = ) : x(x), y(y), z(z) { }
};
Point operator - (Point A, Point B)
{
return Point(A.x - B.x, A.y - B.y, A.z - B.z);
}
double dis(Point A, Point B)
{
double x = A.x - B.x;
double y = A.y - B.y;
double z = A.z - B.z;
return sqrt(x * x + y * y + z * z);
}
int n;
Point p[MAXN];
double SA(Point start)
{
double delta = 100.0;
double ans = 1e20;
while(delta > eps)
{
int d = ;
for(int i=;i<n;i++)
{
if(dis(p[i], start) > dis(p[d], start))
d = i;
}
double r = dis(start, p[d]);
ans = min(ans, r);
start.x += (p[d].x - start.x) / r * delta;
start.y += (p[d].y - start.y) / r * delta;
start.z += (p[d].z - start.z) / r * delta;
delta *= 0.98;
}
return ans;
}
int main()
{
int T, kcase = ;
//scanf("%d", &T);
while(scanf("%d", &n) && n)
{
//scanf("%d", &n);
for(int i=;i<n;i++)
scanf("%lf%lf%lf", &p[i].x, &p[i].y, &p[i].z);
printf("%.8f\n", SA(Point(,,)));
}
return ;
}

这有一个严格按模拟退火的定义写的(精度较低,但更好理解

#include<bits/stdc++.h>
#define rep(i, n) for(int i = 1, i##_end_ = (n); i <= i##_end_; ++i)
using namespace std;
typedef pair<int, int> pii;
typedef long long ll; const double eps = 1e-;
int sgn(double x) {
if(fabs(x) < eps) return ;
return x < ? - : ;
}
struct Point {
double x, y, z;
Point(double xp=, double yp=, double zp=): x(xp), y(yp), z(zp) { }
Point operator + (const Point& rhs) const { return Point(x+rhs.x, y+rhs.y, z+rhs.z); }
Point operator - (const Point& rhs) const { return Point(x-rhs.x, y-rhs.y, z-rhs.z); }
Point operator * (const double& k) const { return Point(x*k, y*k, z*k); }
Point operator / (const double& k) const { return Point(x/k, y/k, z/k); }
bool operator < (const Point& rhs) const { return x < rhs.x || (x==rhs.x && y<rhs.y) || (x==rhs.x&&y==rhs.y&&z<rhs.z); }
bool operator == (const Point& rhs) const {return sgn(x - rhs.x) == && sgn(y - rhs.y) == && sgn(z-rhs.z)==; }
void scan() { scanf("%lf%lf%lf", &x, &y, &z); }
};
typedef Point Vector; double dot(Vector x, Vector y) { return x.x*y.x + x.y*y.y + x.z*y.z; }
double length(Vector x) { return sqrt(dot(x, x)); }
double dist2(Point A, Point B) { return dot(A - B, A - B); }
// Circle
struct Circle {
Point o;
double r;
Circle(Point O, double R): o(O), r(R) { }
}; mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); double Eval(const vector<Point>& pt, Point o) {
double res = ;
for(auto g : pt) res = max(res, dist2(g, o));
return res;
}
uniform_real_distribution<double> rgen(0.0, 1.0);
double Rand(){ return rgen(rng); } Circle MinCircleAnneal(const vector<Point>& pt, double T, double dec, double ed) {
Point pcur, pbest, pnew; int sz = pt.size();
for(auto g : pt) pcur = pcur + g;
pbest = pcur = pcur / sz; double vcur = Eval(pt, pcur), vnew, vbest = vcur; while(T > ed) {
pnew = pcur + Point((Rand()*2.0-) * T, (Rand()*2.0-1.0) * T, (Rand()*2.0-) * T);
vnew = Eval(pt, pnew);
if(vnew <= vbest) vbest = vcur = vnew, pbest = pcur = pnew;
if(vnew <= vcur || Rand() < exp(-(vnew-vcur)/T))
vcur = vnew, pcur = pnew;
T *= dec;
} return Circle(pbest, sqrt(vbest));
} int n;
int main() {
scanf("%d", &n);
vector<Point> p(n);
for(int i = ; i < n; ++i) p[i].scan();
double ans = 1e13;
rep(i, ) {
Circle cir = MinCircleAnneal(p, 100000.0, 0.999, 3e-);
ans = min(ans, cir.r);
}
printf("%.10f\n", ans); return ;
}

2、三分套三分套三分

代码也很好理解,直接看代码吧

/*
三分求球的最小覆盖
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const ll mod=;
const double eps=1e-;
int n;
double x[],y[],z[];
double dis3(double a,double b,double c){
double ans=;
for(int i=;i<=n;i++){
ans=max(ans,(x[i]-a)*(x[i]-a)+(y[i]-b)*(y[i]-b)+(z[i]-c)*(z[i]-c));
}
return ans;
}
double dis2(double a,double b){
double l=-;
double r=;
double ans=;
while(r-l>=eps){
double rmid=(r+l)/;
double lmid=(l+rmid)/;
if(dis3(a,b,lmid)<dis3(a,b,rmid)){
r=rmid;
}
else l=lmid;
}
return dis3(a,b,l);
}
double dis(double a){
double l=-;
double r=;
while(r-l>=eps){
double rmid=(r+l)/;
double lmid=(l+rmid)/;
if(dis2(a,lmid)<dis2(a,rmid)){
r=rmid;
}
else l=lmid;
}
return dis2(a,l);
}
int main(){
// int n;
scanf("%d",&n);
for(int i=;i<=n;i++)scanf("%lf%lf%lf",&x[i],&y[i],&z[i]);
double l=-;
double r=;
while(r-l>=eps){
double rmid=(r+l)/;
double lmid=(l+rmid)/;
if(dis(lmid)<dis(rmid)){
r=rmid;
}
else l=lmid;
}
printf("%.8f\n",sqrt(dis(l)));
return ;
}

不管用上面哪种方法,都需要结合题目的精度要求,调节参数,达到精度和时间的平衡。

1. http://www.voidcn.com/article/p-ffokglab-uy.html

2. https://www.cnblogs.com/MekakuCityActor/p/10613934.html

3. https://www.cnblogs.com/heisenberg-/p/6827790.html

最小球覆盖——模拟退火&&三分套三分套三分的更多相关文章

  1. POJ 最小球覆盖 模拟退火

    最小球覆盖:用半径最小的球去覆盖所有点. 纯粹的退火算法,是搞不定的,精度不够,不然就会TLE,根本跑不出答案来. 任取一点为球心,然后一点点靠近最远点.其实这才是最主要的. 因为:4个点确定一个球, ...

  2. D.Country Meow 最小球覆盖 三分套三分套三分 && 模拟退火

    // 2019.10.3 // 练习题:2018 ICPC 南京现场赛 D Country Meow 题目大意 给定空间内 N 个点,求某个点到 N 个点的距离最大值的最小值.   思路 非常裸的最小 ...

  3. HDU5126---stars (CDQ套CDQ套 树状数组)

    题意:Q次操作,三维空间内 每个星星对应一个坐标,查询以(x1,y1,z1) (x2,y2,z2)为左下顶点 .右上顶点的立方体内的星星的个数. 注意Q的范围为50000,显然离散化之后用三维BIT会 ...

  4. Super Star(最小球覆盖)

    Super Star http://poj.org/problem?id=2069 Time Limit: 1000MS   Memory Limit: 65536K Total Submission ...

  5. POJ2069 最小球覆盖 几何法和退火法

    对这种问题不熟悉的读者 可以先去看一看最小圆覆盖的问题 ZOJ1450 现在我们来看最小球覆盖问题POJ2069 题目很裸,给30个点 求能覆盖所有点的最小球的半径. 先给出以下几个事实: 1.对于一 ...

  6. 2022-08-25-cdn套中套

    layout: post cid: 19 title: cdn套中套 slug: 19 date: 2022/08/25 20:32:00 updated: 2022/08/26 11:20:20 s ...

  7. POJ2069 最小球体覆盖, 模拟退火

    只是套了个模板,模拟退火具体的过程真心不懂阿 //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler #in ...

  8. hihocoder 1142 三分求极值【三分算法 模板应用】

    #1142 : 三分·三分求极值 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 这一次我们就简单一点了,题目在此: 在直角坐标系中有一条抛物线y=ax^2+bx+c和一 ...

  9. Gym - 101981D The 2018 ICPC Asia Nanjing Regional Contest D.Country Meow 最小球覆盖

    题面 题意:给你100个三维空间里的点,让你求一个点,使得他到所有点距离最大的值最小,也就是让你找一个最小的球覆盖掉这n个点 题解:红书模板题,这题也因为数据小,精度也不高,所以也可以用随机算法,模拟 ...

随机推荐

  1. 第十五节:Asp.Net Core中的各种过滤器(授权、资源、操作、结果、异常)

    一. 简介 1. 说明 提到过滤器,通常是指请求处理管道中特定阶段之前或之后的代码,可以处理:授权.响应缓存(对请求管道进行短路,以便返回缓存的响应). 防盗链.本地化国际化等,过滤器用于横向处理业务 ...

  2. MATLAB datenum日期转换为Python日期

    摘要 MATLAB datenum时间格式参数众多,本文只简单关注 units 参数,即基准年份和计时度量(天.小时). 命令行演示在 ipython 和 Octave 中进行. 示例1:小时制,基准 ...

  3. using 语句(C# 参考)(转载)

    using 语句 提供可确保正确使用 IDisposable对象的方便语法. 示例 下面的示例演示如何使用 using 语句. using (var font1 = new Font("Ar ...

  4. java之maven之maven的使用

    这里使用的工具是 myeclipse ,所以这里讲的是在 myeclipse 上使用maven. 1.什么是仓库? 用于存放依赖包.配置文件.其他插件等. 项目添加依赖时,默认从 本地仓库 读取依赖包 ...

  5. [K8s 1.9实践]Kubeadm 1.9 HA 高可用 集群 本地离线镜像部署

    k8s介绍 k8s 发展速度很快,目前很多大的公司容器集群都基于该项目,如京东,腾讯,滴滴,瓜子二手车,北森等等. kubernetes1.9版本发布2017年12月15日,每是那三个月一个迭代, W ...

  6. 如何在ppt全屏演示时仍然显示任务栏?

    相信做过ppt演讲的人会有这样的体会:有的时候希望全屏ppt时不要直接霸占全部的屏幕,至少希望能够看到任务栏,这样就可以仍然方便切换程序. 如何实现呢? 很简单,看下图吧:) https://www. ...

  7. 2019 游族网络java面试笔试题 (含面试题解析)

      本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.游族网络等公司offer,岗位是Java后端开发,因为发展原因最终选择去了游族网络,入职一年时间了,也成为了面 ...

  8. java 判断虚拟网卡物理网卡

    读取注册表方式,jregistrykey.jar与jregistrykey.dll.通过“characteristics”值确定虚拟网卡还是物理网卡.该值在注册表的位置HKEY_LOCAL_MACHI ...

  9. Django 连接 MySQL 数据库及常见报错解决

    目录 Django 连接 MySQL数据库及常见报错解决 终端或者数据库管理工具连接 MySQL ,并新建项目所需数据库 安装访问 MySQL 的 Python 模块 Django 相关配置 可能会遇 ...

  10. DataPipeline丨LinkedIn元数据之旅的最新进展—Data Hub

    作者:Mars Lan, Seyi Adebajo, Shirshanka Das 译者: DataPiepline yaran 作为全球最大的职场社交平台,LinkedIn的数据团队不断致力于扩展其 ...