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;
}
posted @ 2021-07-17 10:41  wljss  阅读(52)  评论(0编辑  收藏  举报