题目

给出 $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个点且等距

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

  1. #include <iostream>
  2. #include <cstring>
  3. #include <cstdlib>
  4. #include <cstdio>
  5. #include <vector>
  6. #include <queue>
  7. #include <stack>
  8. #include <map>
  9. #include <cmath>
  10. #include <set>
  11. #define LL long long
  12. using namespace std;
  13. const int MAXN = ;
  14. const double eps = 1e-;
  15. struct Point
  16. {
  17. double x, y, z;
  18. Point(double x = , double y = , double z = ) : x(x), y(y), z(z) { }
  19. };
  20. Point operator - (Point A, Point B)
  21. {
  22. return Point(A.x - B.x, A.y - B.y, A.z - B.z);
  23. }
  24. double dis(Point A, Point B)
  25. {
  26. double x = A.x - B.x;
  27. double y = A.y - B.y;
  28. double z = A.z - B.z;
  29. return sqrt(x * x + y * y + z * z);
  30. }
  31. int n;
  32. Point p[MAXN];
  33. double SA(Point start)
  34. {
  35. double delta = 100.0;
  36. double ans = 1e20;
  37. while(delta > eps)
  38. {
  39. int d = ;
  40. for(int i=;i<n;i++)
  41. {
  42. if(dis(p[i], start) > dis(p[d], start))
  43. d = i;
  44. }
  45. double r = dis(start, p[d]);
  46. ans = min(ans, r);
  47. start.x += (p[d].x - start.x) / r * delta;
  48. start.y += (p[d].y - start.y) / r * delta;
  49. start.z += (p[d].z - start.z) / r * delta;
  50. delta *= 0.98;
  51. }
  52. return ans;
  53. }
  54. int main()
  55. {
  56. int T, kcase = ;
  57. //scanf("%d", &T);
  58. while(scanf("%d", &n) && n)
  59. {
  60. //scanf("%d", &n);
  61. for(int i=;i<n;i++)
  62. scanf("%lf%lf%lf", &p[i].x, &p[i].y, &p[i].z);
  63. printf("%.8f\n", SA(Point(,,)));
  64. }
  65. return ;
  66. }

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

  1. #include<bits/stdc++.h>
  2. #define rep(i, n) for(int i = 1, i##_end_ = (n); i <= i##_end_; ++i)
  3. using namespace std;
  4. typedef pair<int, int> pii;
  5. typedef long long ll;
  6.  
  7. const double eps = 1e-;
  8. int sgn(double x) {
  9. if(fabs(x) < eps) return ;
  10. return x < ? - : ;
  11. }
  12. struct Point {
  13. double x, y, z;
  14. Point(double xp=, double yp=, double zp=): x(xp), y(yp), z(zp) { }
  15. Point operator + (const Point& rhs) const { return Point(x+rhs.x, y+rhs.y, z+rhs.z); }
  16. Point operator - (const Point& rhs) const { return Point(x-rhs.x, y-rhs.y, z-rhs.z); }
  17. Point operator * (const double& k) const { return Point(x*k, y*k, z*k); }
  18. Point operator / (const double& k) const { return Point(x/k, y/k, z/k); }
  19. 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); }
  20. bool operator == (const Point& rhs) const {return sgn(x - rhs.x) == && sgn(y - rhs.y) == && sgn(z-rhs.z)==; }
  21. void scan() { scanf("%lf%lf%lf", &x, &y, &z); }
  22. };
  23. typedef Point Vector;
  24.  
  25. double dot(Vector x, Vector y) { return x.x*y.x + x.y*y.y + x.z*y.z; }
  26. double length(Vector x) { return sqrt(dot(x, x)); }
  27. double dist2(Point A, Point B) { return dot(A - B, A - B); }
  28. // Circle
  29. struct Circle {
  30. Point o;
  31. double r;
  32. Circle(Point O, double R): o(O), r(R) { }
  33. };
  34.  
  35. mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
  36.  
  37. double Eval(const vector<Point>& pt, Point o) {
  38. double res = ;
  39. for(auto g : pt) res = max(res, dist2(g, o));
  40. return res;
  41. }
  42. uniform_real_distribution<double> rgen(0.0, 1.0);
  43. double Rand(){ return rgen(rng); }
  44.  
  45. Circle MinCircleAnneal(const vector<Point>& pt, double T, double dec, double ed) {
  46. Point pcur, pbest, pnew;
  47.  
  48. int sz = pt.size();
  49. for(auto g : pt) pcur = pcur + g;
  50. pbest = pcur = pcur / sz;
  51.  
  52. double vcur = Eval(pt, pcur), vnew, vbest = vcur;
  53.  
  54. while(T > ed) {
  55. pnew = pcur + Point((Rand()*2.0-) * T, (Rand()*2.0-1.0) * T, (Rand()*2.0-) * T);
  56. vnew = Eval(pt, pnew);
  57. if(vnew <= vbest) vbest = vcur = vnew, pbest = pcur = pnew;
  58. if(vnew <= vcur || Rand() < exp(-(vnew-vcur)/T))
  59. vcur = vnew, pcur = pnew;
  60. T *= dec;
  61. }
  62.  
  63. return Circle(pbest, sqrt(vbest));
  64. }
  65.  
  66. int n;
  67. int main() {
  68. scanf("%d", &n);
  69. vector<Point> p(n);
  70. for(int i = ; i < n; ++i) p[i].scan();
  71. double ans = 1e13;
  72. rep(i, ) {
  73. Circle cir = MinCircleAnneal(p, 100000.0, 0.999, 3e-);
  74. ans = min(ans, cir.r);
  75. }
  76. printf("%.10f\n", ans);
  77.  
  78. return ;
  79. }

2、三分套三分套三分

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

  1. /*
  2. 三分求球的最小覆盖
  3. */
  4. #include<iostream>
  5. #include<cstdio>
  6. #include<cstring>
  7. #include<algorithm>
  8. #include<cmath>
  9. using namespace std;
  10. typedef long long ll;
  11. const ll mod=;
  12. const double eps=1e-;
  13. int n;
  14. double x[],y[],z[];
  15. double dis3(double a,double b,double c){
  16. double ans=;
  17. for(int i=;i<=n;i++){
  18. ans=max(ans,(x[i]-a)*(x[i]-a)+(y[i]-b)*(y[i]-b)+(z[i]-c)*(z[i]-c));
  19. }
  20. return ans;
  21. }
  22. double dis2(double a,double b){
  23. double l=-;
  24. double r=;
  25. double ans=;
  26. while(r-l>=eps){
  27. double rmid=(r+l)/;
  28. double lmid=(l+rmid)/;
  29. if(dis3(a,b,lmid)<dis3(a,b,rmid)){
  30. r=rmid;
  31. }
  32. else l=lmid;
  33. }
  34. return dis3(a,b,l);
  35. }
  36. double dis(double a){
  37. double l=-;
  38. double r=;
  39. while(r-l>=eps){
  40. double rmid=(r+l)/;
  41. double lmid=(l+rmid)/;
  42. if(dis2(a,lmid)<dis2(a,rmid)){
  43. r=rmid;
  44. }
  45. else l=lmid;
  46. }
  47. return dis2(a,l);
  48. }
  49. int main(){
  50. // int n;
  51. scanf("%d",&n);
  52. for(int i=;i<=n;i++)scanf("%lf%lf%lf",&x[i],&y[i],&z[i]);
  53. double l=-;
  54. double r=;
  55. while(r-l>=eps){
  56. double rmid=(r+l)/;
  57. double lmid=(l+rmid)/;
  58. if(dis(lmid)<dis(rmid)){
  59. r=rmid;
  60. }
  61. else l=lmid;
  62. }
  63. printf("%.8f\n",sqrt(dis(l)));
  64. return ;
  65. }

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

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. 基于网络拓扑图通过RCMS对网络进行配置

    目录 基于网络拓扑图通过RCMS对网络进行配置 一些基本命令 对网络拓扑图1的简单配置 二层交换机S3 三层交换机 S2 实验结果 对网络拓扑图2的简单配置 NAT.ACL配置公网IP 基于网络拓扑图 ...

  2. 前端编程的核心问题是数据与UI的绑定

    1.静态页面---静态绑定 2.js dom强修改--js重置绑定: 3.chymeleaf--预处理html+特殊语言绑定: 4.react--组建化UI.js与其他语言形式绑定

  3. Logstash配置文件修改自动加载和指定目录进行启动

    检查配置并启动Logstash,修改后自动加载 指定配置文件目录并启动Logstash

  4. php 无线分类 根据子级找父级

    public function transform($item){ //查询数据 $position = AdminAccess::where('id',$item)->first(); $re ...

  5. 数据库‘master’中拒绝CREATE DATABASE权限

    今天在创建数据库的时候,遇到了没有创建数据库权限的问题,后来百度了一下解决了该问题. 1.先用windows身份验证登录,在安全性下面的找到自己创建的登录名,双击,在弹出的对话框中为它赋予权限. 2. ...

  6. C#实现服务器间文件同步

    using System.IO; /// <summary> /// 远程登陆服务器 /// </summary> /// <param name="remot ...

  7. Java 11 新特性介绍

    Java 11 已于 2018 年 9 月 25 日正式发布,之前在Java 10 新特性介绍中介绍过,为了加快的版本迭代.跟进社区反馈,Java 的版本发布周期调整为每六个月一次——即每半年发布一个 ...

  8. 锤子剪刀布pat-1018

    题目描述 大家应该都会玩“锤子剪刀布”的游戏:现给出两人的交锋记录,请统计双方的胜.平.负次数,并且给出双方分别出什么手势的胜算最大. 输入描述: 输入第1行给出正整数N(<=105),即双方交 ...

  9. 【转】用Python做股市量化策略投资数据分析

    金融量化分析介绍     本文摘要; 金融量化分析介绍 1.什么是金融量化分析 2.金融量化分析可以干什么 3.为什么将python运用于金融 4.常用库简介 1.什么是金融量化分析 从标题中我们可以 ...

  10. js 递归遍历对象 插入属性 遍历树结构

    // 向 info下面 每一项 插入 isShow test() { const _this = this; _this.info.isShow = false; let iteration = fu ...