我是靠谱客的博主 优秀水杯,最近开发中收集的这篇文章主要介绍[GYM101981D - 2018ICPC南京] Country Meow(三分 / 模拟退火),觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
传送门:Country Meow
题意为,在一个三维坐标系中,给定 n 个点,要求找到一个点,使得该点与这 n 个点中距离该点最远的点的距离最小,给出这个最小的距离值。
实际上,这个问题就相当于最小球覆盖问题。有三种做法:
① 最小球覆盖模板。计算几何模板,非常暴力。但我没有。
② 三分。求距离的函数是个单峰函数,可以通过三分查找来找到极值。但由于有 x、y、z 三个变量需要控制,所以采用三层嵌套的三分。
③ 模拟退火。随机化算法,在单峰的情况下,不断移动至极值。
- 三分
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 2e2;
const double inf = 1e15;
const double eps = 1e-3;
struct Point
{
double x, y, z;
Point() {}
Point(double x, double y, double z): x(x), y(y), z(z) {}
}p[maxn];
int n;
double ans;
void read()
{
scanf("%d", &n);
double x, y, z;
for(int i = 0; i < n; ++i)
{
scanf("%lf%lf%lf", &x, &y, &z);
p[i] = Point(x, y, z);
}
}
double dis(Point u, Point v)
{
double dx = u.x - v.x;
double dy = u.y - v.y;
double dz = u.z - v.z;
return dx*dx + dy*dy + dz*dz;
}
double calDis(double x, double y, double z)
{
double maxDis = 0;
Point tp = Point(x, y, z);
for(int i = 0; i < n; ++i)
maxDis = max(maxDis, dis(tp, p[i]));
return maxDis;
}
double threeDivideZ(double x, double y)
{
double left = -1e6, right = 1e6;
double lmid, rmid, val1, val2;
double ret = inf;
for(int i = 0; i < 50; ++i)
{
lmid = left + (right-left)/3;
rmid = right - (right-left)/3;
val1 = calDis(x, y, lmid);
val2 = calDis(x, y, rmid);
ret = min(ret, min(val1, val2));
if(val1 > val2)
left = lmid;
else
right = rmid;
}
return ret;
}
double threeDivideY(double x)
{
double left = -1e6, right = 1e6;
double lmid, rmid, val1, val2;
double ret = inf;
for(int i = 0; i < 50; ++i)
{
lmid = left + (right-left)/3;
rmid = right - (right-left)/3;
val1 = threeDivideZ(x, lmid);
val2 = threeDivideZ(x, rmid);
ret = min(ret, min(val1, val2));
if(val1 > val2)
left = lmid;
else
right = rmid;
}
return ret;
}
void solve()
{
double left = -1e6, right = 1e6;
double lmid, rmid, val1, val2;
for(int i = 0; i < 50; ++i)
{
lmid = left + (right-left)/3;
rmid = right - (right-left)/3;
val1 = threeDivideY(lmid);
val2 = threeDivideY(rmid);
if(val1 > val2)
left = lmid;
else
right = rmid;
}
ans = min(val1, val2);
printf("%.6fn", sqrt(ans));
}
int main()
{
read();
solve();
return 0;
}
- 模拟退火
K
const double inf = 1e23;
const double eps = 1e-6;
const double T0 = 1e6;
struct Point
{
double x, y, z;
Point() {}
Point(double x, double y, double z): x(x), y(y), z(z) {}
}p[maxn];
int n;
void read()
{
scanf("%d", &n);
double x, y, z;
for(int i = 0; i < n; ++i)
{
scanf("%lf%lf%lf", &x, &y, &z);
p[i] = Point(x, y, z);
}
}
double dis(Point u, Point v)
{
double dx = u.x - v.x;
double dy = u.y - v.y;
double dz = u.z - v.z;
return dx*dx + dy*dy + dz*dz;
}
void solve()
{
Point sp = Point(0, 0, 0);
double T = T0, delta = 0.99;
double ans = inf;
while(T > eps)
{
Point tp = p[0];
for(int i = 1; i < n; ++i)
if(dis(sp, tp) < dis(sp, p[i]))
tp = p[i];
ans = min(ans, dis(sp, tp));
sp.x += (tp.x - sp.x) / T0 * T;
sp.y += (tp.y - sp.y) / T0 * T;
sp.z += (tp.z - sp.z) / T0 * T;
T *= delta;
}
printf("%.9fn", sqrt(ans));
}
int main()
{
read();
solve();
return 0;
}
最后
以上就是优秀水杯为你收集整理的[GYM101981D - 2018ICPC南京] Country Meow(三分 / 模拟退火)的全部内容,希望文章能够帮你解决[GYM101981D - 2018ICPC南京] Country Meow(三分 / 模拟退火)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复