最小球覆盖——模拟退火&&三分套三分套三分
题目
给出 $N(1 \leq N \leq 100)$ 个点的坐标 $x_i,y_i,z_i$($-100000 \leq x_i,y_i,z_i \leq 100000$),求包围全部点的最小的球。
分析
方法一:模拟退火
模拟退火是 解决最小球覆盖的经典方法,效果也非常好。
随机得到球的中心,如果更小的半径或设定的概率,则转移。(详细解释见链接)
//这个代码严格说不是模拟退火
有一个事实:最小球的球心,它不然是一个确定的点,就是距它最远的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
最小球覆盖——模拟退火&&三分套三分套三分的更多相关文章
- POJ 最小球覆盖 模拟退火
最小球覆盖:用半径最小的球去覆盖所有点. 纯粹的退火算法,是搞不定的,精度不够,不然就会TLE,根本跑不出答案来. 任取一点为球心,然后一点点靠近最远点.其实这才是最主要的. 因为:4个点确定一个球, ...
- D.Country Meow 最小球覆盖 三分套三分套三分 && 模拟退火
// 2019.10.3 // 练习题:2018 ICPC 南京现场赛 D Country Meow 题目大意 给定空间内 N 个点,求某个点到 N 个点的距离最大值的最小值. 思路 非常裸的最小 ...
- HDU5126---stars (CDQ套CDQ套 树状数组)
题意:Q次操作,三维空间内 每个星星对应一个坐标,查询以(x1,y1,z1) (x2,y2,z2)为左下顶点 .右上顶点的立方体内的星星的个数. 注意Q的范围为50000,显然离散化之后用三维BIT会 ...
- Super Star(最小球覆盖)
Super Star http://poj.org/problem?id=2069 Time Limit: 1000MS Memory Limit: 65536K Total Submission ...
- POJ2069 最小球覆盖 几何法和退火法
对这种问题不熟悉的读者 可以先去看一看最小圆覆盖的问题 ZOJ1450 现在我们来看最小球覆盖问题POJ2069 题目很裸,给30个点 求能覆盖所有点的最小球的半径. 先给出以下几个事实: 1.对于一 ...
- 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 ...
- POJ2069 最小球体覆盖, 模拟退火
只是套了个模板,模拟退火具体的过程真心不懂阿 //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler #in ...
- hihocoder 1142 三分求极值【三分算法 模板应用】
#1142 : 三分·三分求极值 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 这一次我们就简单一点了,题目在此: 在直角坐标系中有一条抛物线y=ax^2+bx+c和一 ...
- Gym - 101981D The 2018 ICPC Asia Nanjing Regional Contest D.Country Meow 最小球覆盖
题面 题意:给你100个三维空间里的点,让你求一个点,使得他到所有点距离最大的值最小,也就是让你找一个最小的球覆盖掉这n个点 题解:红书模板题,这题也因为数据小,精度也不高,所以也可以用随机算法,模拟 ...
随机推荐
- 基于网络拓扑图通过RCMS对网络进行配置
目录 基于网络拓扑图通过RCMS对网络进行配置 一些基本命令 对网络拓扑图1的简单配置 二层交换机S3 三层交换机 S2 实验结果 对网络拓扑图2的简单配置 NAT.ACL配置公网IP 基于网络拓扑图 ...
- 前端编程的核心问题是数据与UI的绑定
1.静态页面---静态绑定 2.js dom强修改--js重置绑定: 3.chymeleaf--预处理html+特殊语言绑定: 4.react--组建化UI.js与其他语言形式绑定
- Logstash配置文件修改自动加载和指定目录进行启动
检查配置并启动Logstash,修改后自动加载 指定配置文件目录并启动Logstash
- php 无线分类 根据子级找父级
public function transform($item){ //查询数据 $position = AdminAccess::where('id',$item)->first(); $re ...
- 数据库‘master’中拒绝CREATE DATABASE权限
今天在创建数据库的时候,遇到了没有创建数据库权限的问题,后来百度了一下解决了该问题. 1.先用windows身份验证登录,在安全性下面的找到自己创建的登录名,双击,在弹出的对话框中为它赋予权限. 2. ...
- C#实现服务器间文件同步
using System.IO; /// <summary> /// 远程登陆服务器 /// </summary> /// <param name="remot ...
- Java 11 新特性介绍
Java 11 已于 2018 年 9 月 25 日正式发布,之前在Java 10 新特性介绍中介绍过,为了加快的版本迭代.跟进社区反馈,Java 的版本发布周期调整为每六个月一次——即每半年发布一个 ...
- 锤子剪刀布pat-1018
题目描述 大家应该都会玩“锤子剪刀布”的游戏:现给出两人的交锋记录,请统计双方的胜.平.负次数,并且给出双方分别出什么手势的胜算最大. 输入描述: 输入第1行给出正整数N(<=105),即双方交 ...
- 【转】用Python做股市量化策略投资数据分析
金融量化分析介绍 本文摘要; 金融量化分析介绍 1.什么是金融量化分析 2.金融量化分析可以干什么 3.为什么将python运用于金融 4.常用库简介 1.什么是金融量化分析 从标题中我们可以 ...
- js 递归遍历对象 插入属性 遍历树结构
// 向 info下面 每一项 插入 isShow test() { const _this = this; _this.info.isShow = false; let iteration = fu ...