玄学算法——模拟退火
引入
有时我们需要解决一些看似无法解决的问题,比如这题:P1337 [JSOI2004] 平衡点 / 吊打XXX - 洛谷。
总不能把每个坐标都枚举过去吧。(当然这道题也有许多其他优秀的算法。)
这时就需要玄学登场了。
模拟退火
什么是退火?
退火是一种金属热处理工艺,指的是将金属缓慢加热到一定温度,保持足够时间,然后以适宜速度冷却。广义上说,退火是一种对材料的热处理工艺,包括金属材料、非金属材料。而且新材料的退火目的也与传统金属退火存在异同。
——百度百科
模拟退火要做的就是在当前解的基础上 按当前温度的幅度来随机情况 并判断此解的优劣。形式化地说:
有参数 \(T_0\) 表示初始温度,\(T_k\) 表示终止温度,\(d\) 表示降温系数。\(S\) 表示当前最优解,\(T\) 表示当前温度。注意 \(T_0>T_k\)(即整个退火是降温操作)。
每次通过随机化生成一个解 \(S'\),那么接受这个解的概率为:
其中 \(\Delta\) 表示两个解的差。由于 \(e^{-x}<1~(x>0)\) 且递减,所以 \(\Delta\) 越大(解越差),接受概率越小。同时 \(T\) 越大,接受概率越大(更狂、更不理智、更赌)。(模拟退火含金量最高的地方。好像与玻尔兹曼分布有关。其实不用了解太多。)
那么怎么退火?
- \(T\gets T_0\)。
- 随机化:
- 随机解并按概率接受解。随机解时应按 \(T\) 的大小控制随机幅度(具体看代码)。
- \(T\gets T\times d\)。
- 重复上一步(随机化),如果 \(T<T_k\),算法结束。
#include <iostream> #include <cmath> #include <ctime> using namespace std; typedef double d; // 分别为:降温系数、开始温度、结束温度、用于卡时的。 const d down=0.997,Beg=1e5,End=1e-15,MAX_TIME=0.8; // 降温系数一般接近 1(徐徐降温),开始温度一般足够大(看数据范围),结束温度足够小(看答案精度),卡时常数略小于时限(单位 秒)。 const int N=2145; int n; d ansx,ansy,answ; struct node { int x,y,w; }; node a[N]; d calc(d x,d y)// 计算解的优劣 { d r=0,dx,dy; for(int i=1;i<=n;i++) { dx=x-a[i].x; dy=y-a[i].y; r+=sqrt(dx*dx+dy*dy)*a[i].w; } return r; } void SA() { d t=Beg; while(t>End) { d ex=ansx+(rand()*2-RAND_MAX)*t,ey=ansy+(rand()*2-RAND_MAX)*t;// 按当前温度随机化解 // printf("%.5lf %.5lf\n",ex,ey); d ew=calc(ex,ey);// 计算优劣 d de=ew-answ;// 计算优劣差异 if(de<0)// 随机的解更好 { ansx=ex,ansy=ey,answ=ew;// 接受 } else if(exp(-de/t)*RAND_MAX>rand())// 否则以概率接受 { ansx=ex,ansy=ey; } t*=down;// 降温 } } inline void init() { srand(time(NULL)); srand(rand()+114514); srand(rand()+1919810); srand(rand()); } int main() { init(); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d %d %d",&a[i].x,&a[i].y,&a[i].w); ansx+=a[i].x; ansy+=a[i].y; } ansx/=n,ansy/=n;// 以平均数为初始解 answ=calc(ansx,ansy); while((double)clock()/CLOCKS_PER_SEC<MAX_TIME)SA();// 卡时,有时间就一直模拟退火 printf("%.3lf %.3lf",ansx,ansy);// 输出解 return 0; }
卡时寄巧
定一个略小于时限的卡时常数(必须满足:卡时常数 \(+\) 单次模拟退火用时 \(<\) 时限)。一般定 \(0.8\sim0.9\)(时限 \(1~\text s\))。
这样只要还有时间,就一直跑模拟退火(增加找到解的概率)。
后记
初学模拟退火,以上就是我的心得体会。以后有新东西会补上。
EOF
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具