模拟退火
作者:互联网
模拟退火
模拟退火是一种 著名的 玄学的随机化算法,其建立在物理中退火过程的基础上
其时间复杂度为 \(O(\text{时限})\) ,正确概率为 \(\text{(参数优秀程度+阳寿)}\%\)
通常人们使用造数据+手动二分调参的方式来提高正确率
这种算法是 \(oier\) 在比赛中的不二选择
#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