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,now,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=now=suan(sx,sy);//初始平衡位置设为平均值 
	while(Time--)//多次模拟退火 
	{
		now=Ans;X0=sx;Y0=sy;//拿之前的最优解做初始值。X0 Y0为当前位置,相当于是搜索过程中当前状态。 sx sy是之前算出的最好的的位置 。now是当前在的位置的suan值
		for(DB T=100000;T>eps;T*=D)
		{//以下为重点 
			X1=X0+YY;Y1=Y0+YY;tmp=suan(X1,Y1);//YY搜索改变量  X1 Y1下一个位置 ,tmp为X1 Y1的suan函数值
			if(tmp<Ans/*Ans 所有过程中最优的*/)Ans=tmp,sx=X1,sy=Y1;//更新搜索过程中记录最优答案 。这一步仅仅更新最优答案,不影响下一步走不走的决策。
			/*考虑走不走到X1 Y1  或符号右边相当于是不满足情况下看概率转移*/if(tmp<now||exp((now-tmp)/T)/*到了"||"的右边就满足了ans<tmp ,T越大,(now-tmp)/T越接近0,exp((now-tmp)/T)越大越接近1*/>(DB)rand()/RAND_MAX/*大于号右边:得到一个0到1的随机小数*/)now=tmp,X0=X1,Y0=Y1/*选择走*/;
		}
	}
	printf("%.3Lf %.3Lf",sx,sy);
	return 0;
}
posted @ 2021-07-17 10:41  wljss  阅读(85)  评论(0)    收藏  举报