模拟退火
模拟退火#
模拟退火是一种 著名的 玄学的随机化算法,其建立在物理中退火过程的基础上
其时间复杂度为 (因为要跑满确保正确性) ,正确概率为
通常人们使用造数据+手动二分调参的方式来提高正确率
这种算法是 在比赛中骗分的不二选择
一般的套路是小数据跑暴力,大数据贪心+模拟退火
用于卡时:
//MAX_TIME为自定义时间上线 (单位:秒)
while((double)clock/CLOCKS_PER_SEC<MAX_TIME) SimulateAnneal
题#
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;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现