其他分享
首页 > 其他分享> > 模拟退火

模拟退火

作者:互联网

模拟退火

模拟退火是一种 著名的 玄学的随机化算法,其建立在物理中退火过程的基础上

其时间复杂度为 \(O(\text{时限})\) ,正确概率为 \(\text{(参数优秀程度+阳寿)}\%\)

通常人们使用造数据+手动二分调参的方式来提高正确率

这种算法是 \(oier\) 在比赛中的不二选择

UVA10228 A Star not a Tree?

#include<bits/stdc++.h>
using namespace std;

#define down 0.97

const int N=1e5+5;

inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}

int n;
double x[N],y[N];
double ansx,ansy,ans;

//cal函数因题而异,是用于求解某一点的答案
inline double cal(double u,double v){
	double res=0;
	for(int i=1;i<=n;++i){
		res+=sqrt((u-x[i])*(u-x[i])+(v-y[i])*(v-y[i]));
	}
	return res;
}

inline void SimulateAnneal(){
	double t=3000,mt=1e-10;//t指初始温度,mt指结束温度
	double nowx=ansx,nowy=ansy;
	for(;t>=mt;t*=down){//t每次*down表示降温
		double nx=nowx+(rand()*2-RAND_MAX)*t;//常规随机数据
		double ny=nowy+(rand()*2-RAND_MAX)*t;
		double nows=cal(nx,ny);
		double delta=nows-ans;//记录差值
		if(delta<0) ansx=nx,ansy=ny,nowx=nx,nowy=ny,ans=nows;//若当前答案更优,则更新
		else if(exp(-delta/t)*RAND_MAX>rand()) nowx=nx,nowy=ny;//否则概率更新
	}
}

signed main(){
	srand(time(0));
	int T;
	cin>>T;
	for(int i=1;i<=T;++i){
		cin>>n;
		ans=1e9,ansx=ansy=0;
		for(int i=1;i<=n;++i){
			cin>>x[i]>>y[i];
			ansx+=x[i],ansy+=y[i];
		}
		ansx/=n,ansy/=n;//初始答案
		int B=50;
		while(B--) SimulateAnneal();//跑多次模拟退火
		cout<<round(ans)<<endl;
		if(i!=T) cout<<endl;
	}
}

标签:ch,int,double,down,while,模拟退火
来源: https://www.cnblogs.com/into-qwq/p/16488256.html