模拟退火求最小球覆盖和最小圆覆盖
原本在我的认识中,模拟退火一定要有一个随机化在里面。
但是有些模拟退火,你可以清楚地意识到答案是可以向某个方向逼近的,这个时候就不用随机了。
比如像第一道题POJ 2069,这道题求的就是最小球覆盖。
对于任意的初始点,我们都能算出以当前点作为圆心的覆盖半径是多少。
显然,决定这条半径多长的,是所有点中离圆心最远的。
那么我们是不是可以越来越靠近这个最远的点,使得最远的距离最小,也就是球的半径能最小?
答案是肯定的,我们直接慢慢地更新答案即可。
同时我们也套上模拟退火的板子,用一个T来表示那一步移动的步长。
最小圆覆盖当然比三维情况要简单,所以能理解上面的,那道题也就顺便切掉了。
分别附上这两道题的代码:
POJ 2069
#include<cstdio>
#include<cmath>
const int maxn = 35;
const double delta = 0.98;
struct Point
{
double x, y, z;
} s[maxn];
double ansx, ansy, ansz, ans;
int n;
inline double sq(double x)
{
return x * x;
}
double dist(double x, double y, double z, double xx, double yy, double zz)
{
return sqrt(sq(x - xx) + sq(y - yy) + sq(z - zz));
}
int main()
{
while(scanf("%d", &n) == 1 && n)
{
ansx = ansy = ansz = 0;// 取平均值过不了是最骚的
for(int i = 1; i <= n; i++)
{
scanf("%lf%lf%lf", &s[i].x, &s[i].y, &s[i].z);
}
for(double T = 100; T > 1e-15; T = T * delta)// 话说这道题卡精度
{
double maxdist = -1e15; int idx = -1;
for(int i = 1; i <= n; i++)
{
double temp = dist(ansx, ansy, ansz, s[i].x, s[i].y, s[i].z);
if(temp > maxdist)
{
maxdist = temp; idx = i;
}
}
ans = maxdist;
ansx += (s[idx].x - ansx) / maxdist * T;
ansy += (s[idx].y - ansy) / maxdist * T;
ansz += (s[idx].z - ansz) / maxdist * T;
}
printf("%.5lf\n", ans);
}
return 0;
}
HDU 3007
#include<cstdio>
#include<cmath>
const int maxn = 505;
struct Nodes
{
double x, y;
} s[maxn];
double ansx, ansy;
int n;
inline double sq(double x)
{
return x * x;
}
double dist(double x, double y, double xx, double yy)
{
return sqrt(sq(x - xx) + sq(y - yy));
}
int main()
{
while(scanf("%d", &n) == 1 && n)
{
ansx = ansy = 0;
for(int i = 1; i <= n; i++)
{
scanf("%lf%lf", &s[i].x, &s[i].y);
ansx += s[i].x; ansy += s[i].y;
}
ansx /= n; ansy /= n;
const double delta = 0.98;
for(double T = 2018; T > 1e-10; T *= delta)
{
double maxr = -1e10; int idx = -1;
for(int i = 1; i <= n; i++)
{
double temp = dist(ansx, ansy, s[i].x, s[i].y);
if(temp > maxr)
{
maxr = temp; idx = i;
}
}
ansx += (s[idx].x - ansx) / maxr * T;
ansy += (s[idx].y - ansy) / maxr * T;
}
printf("%.2lf %.2lf %.2lf\n", ansx, ansy, dist(ansx, ansy, s[1].x, s[1].y));
}
return 0;
}