P1337 [JSOI2004]平衡点 / 吊打XXX 模拟退火
模拟退火模板题,不会可以看这里
一个位置到所有点的dis*weight的和越小越好
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<ctime>
#define DB long double
#define YY T*(2*rand()-RAND_MAX)
using namespace std;
int n,Time=1;
DB sx,sy,ans,Ans,X0,Y0,X1,Y1,tmp;
const int N=1010;
const DB D=0.97,eps=1e-14;
DB x[N],y[N],w[N];
DB p2(DB x){return x*x;}
DB suan(DB X,DB Y)//衡量当前平衡位置优不优
{
DB res=0;
for(int i=1;i<=n;++i)
res+=sqrt(p2(X-x[i])+p2(Y-y[i]))*w[i];
return res;
}
int main()
{
srand(20030701);cin>>n;
for(int i=1;i<=n;++i)
{
scanf("%Lf%Lf%Lf",&x[i],&y[i],&w[i]);
sx+=x[i];sy+=y[i];
}
sx/=n;sy/=n;Ans=ans=suan(sx,sy);//初始平衡位置设为平均值
while(Time--)//多次模拟退火
{
ans=Ans;X0=sx;Y0=sy;//X0 Y0当前平衡位置,相当于是搜索过程中当前状态 sx sy是最终求出来的平衡位置
for(DB T=100000;T>eps;T*=D)
{//以下为重点
X1=X0+YY;Y1=Y0+YY;tmp=suan(X1,Y1);//YY搜索改变量 X1 Y1下一个平衡位置
if(tmp<Ans/*Ans 所有过程中最优的*/)Ans=tmp,sx=X1,sy=Y1;//搜索过程中记录最优答案
/*考虑走不走到X1 Y1 或符号右边相当于是不满足情况下看概率转移*/if(tmp<ans||exp((ans-tmp)/T)/*到了或的右边就满足了ans<tmp ,T越大,(ans-tmp)/T越接近0,exp((ans-tmp)/T)越大越接近1*/>(DB)rand()/RAND_MAX/*大于号右边:得到一个0到1的随机小数*/)ans=tmp,X0=X1,Y0=Y1/*选择走*/;
}
}
printf("%.3Lf %.3Lf",sx,sy);
return 0;
}