【POJ2069&HDU3007】模拟退火算法之最小球/圆覆盖
启蒙博客:https://blog.csdn.net/AI_BigData_wh/article/details/77943787?locationNum=2&fps=1
POJ2069:最小球覆盖
被精度搞死。。POJ做题经常被精度卡到怀疑人生。。好感-1-1-1...-1
队友的模拟退火的模版好像是错的(但是能过HDU3007,很玄学了)。初识温度的设置不能太大,会影响最终结果的准确度。
ac代码:
#include <iostream>
#include <cmath>
using namespace std;
const int maxn = 40;
const double eps = 1e-7;
const double DINF = 0x7fffffff;
const double initT = 400;//设小了可能会wa,POJ2069开到500会wa,200-400可行
struct Point{
double x, y, z;
Point(double x = 0, double y = 0, double z = 0):x(x),y(y),z(z){}
};
Point p[maxn];
int n;
double dist(Point a, Point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
}
double sa()
{
double ans = DINF, T = initT;//T相当与迭代次数,多次结果更准确
Point ansp = Point(0,0,0);// ansp记录最小球的圆心
while(T > eps)
{
double maxd = -1;
int k = 0;
for(int i = 0; i < n; i++)
if(dist(ansp, p[i]) > maxd)
{
maxd = dist(ansp, p[i]);
k = i;//不单独开一个点maxd记录和当前圆心距离最远的点,会wa,精度问题吧
}
ans = min(ans, maxd);//更新最小半径
ansp.x += (p[k].x-ansp.x)*T/maxd;
ansp.y += (p[k].y-ansp.y)*T/maxd;
ansp.z += (p[k].z-ansp.z)*T/maxd;
T *= 0.98;//降温
}
return ans;
}
int main()
{
//freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
while(scanf("%d", &n))
{
if(n == 0) break;
for(int i = 0; i < n; i++) scanf("%lf %lf %lf", &p[i].x, &p[i].y, &p[i].z);
printf("%.5lf\n", sa());
}
return 0;
}
HDU3007: 最小圆覆盖
数据比较水吧。用队友的模版也能过,两个都贴上吧。!(◎_◎;)
mine:
#include <iostream>
#include <cmath>
using namespace std;
const int maxn = 550;
const double eps = 1e-7;
const double DINF = 0x7fffffff;
const double initT = 400;//设小了可能会wa,POJ2069开到500会wa
struct Point{
double x, y;
Point(double x = 0, double y = 0):x(x),y(y){}
};
Point p[maxn];
int n;
double dist(Point a, Point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double sa()
{
double ans = DINF, T = initT;//T相当与迭代次数,多次结果更准确
Point ansp = Point(0,0);//ansp记录最小球的圆心
while(T > eps)
{
double maxd = -1;
int k = 0;
for(int i = 0; i < n; i++)
if(dist(ansp, p[i]) > maxd)
{
maxd = dist(ansp, p[i]);
k = i;
}
ans = min(ans, maxd);//更新最小半径
ansp.x += (p[k].x-ansp.x)*T/maxd;
ansp.y += (p[k].y-ansp.y)*T/maxd;
T *= 0.98;//降温
}
printf("%.2lf %.2lf %.2lf\n", ansp.x, ansp.y, ans);
}
int main()
{
//freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
while(scanf("%d", &n))
{
if(n == 0) break;
for(int i = 0; i < n; i++) scanf("%lf %lf", &p[i].x, &p[i].y);
sa();
}
return 0;
}
WJX‘s:
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=550;
const double eps=1e-3; //精度
const double start_T=1000; //初始温度
const double rate=0.98; //温度下降速率
struct point
{
double x;
double y;
} p[maxn];
int N;
double dist(point a,point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double solve()
{
double T=start_T;
point ans_p={0,0}; //初始点
double ans=1e99; //预设一个较大值
while(T>eps)
{
point maxd_p=p[1];
for(int i=2;i<=N;i++)
{
if(dist(ans_p,p[i])>dist(ans_p,maxd_p))
maxd_p=p[i];
}
//找到距离ans_p最远的点,maxd_p
ans=min(ans,dist(ans_p,maxd_p));
ans_p.x+=(maxd_p.x-ans_p.x)*(T/start_T); //以一定概率靠近maxd_p
ans_p.y+=(maxd_p.y-ans_p.y)*(T/start_T);
T*=rate;
}
printf("%.2lf %.2lf %.2lf\n", ans_p.x, ans_p.y, ans);
}
int main()
{
//freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
while(scanf("%d",&N) && N)
{
for (int i = 1; i <= N; i++)
scanf("%lf %lf", &p[i].x, &p[i].y);
solve();
}
return 0;
}