题目
大佬说这题可以很好的入门模拟退火
虽然模拟退火不是这题的最佳解
但是确实可以通过这个来理解模拟退火的思想
本题求一个平衡点,我们要找一个点使得∑ni=di∗wi最小(di为i点到该点的距离)。
#include
#include
#include
#include
#define RG register
#define R RG long double
#define RD T*(rand()*2-RAND_MAX)
const int maxn=1009;
const long double D=0.97,EPS=1e-14;//参数。。。模拟退火的核心(但是不会调-_-)
double x[maxn],y[maxn],w[maxn];
int n;
inline long double calc(R x0,R y0)//计算当前选定点的势能
{
R res=0,dx,dy;
for(RG int i=1;i<=n;++i){
dx=x[i]-x0;
dy=y[i]-y0;
res+=sqrt(dx*dx+dy*dy)*w[i];
}
return res;
}
int main()
{
R T,x0,y0,x1,y1,res,ans,best,bx=0,by=0;
RG int i,times=1;
scanf("%d",&n);
for(i=1;i<=n;++i) {
scanf("%lf%lf%lf",&x[i],&y[i],&w[i]);
bx+=x[i];
by+=y[i];
}
best=ans=calc(bx/=n,by/=n);
srand(time(NULL));//保证每次的随机数不一样
while(times--) {
ans=best;
x0=bx;y0=by;
for(T=100000;T>EPS;T*=D)
{
x1=x0+RD;y1=y0+RD;
res=calc(x1,y1);
if(best>res) {
best=res;
bx=x1;
by=y1;
}
if(ans>res||exp((ans-res)/T)>(long double)rand()/RAND_MAX) {
//rand()/RAND_MAX,随机生成一个小于1的数,
//至于这个exp((ans-res)/T)是科学家计算出来的,我们用就好了
ans=res;
x0=x1;
y0=y1;
}
}
}
printf("%.3Lf %.3Lf\n",bx,by);//输出用Lf
return 0;
}