曾几何时,听到模拟退火这种算法,以为它是多么神奇神秘神鬼莫测的算法。
现在才认识到,世界上居然有如此搞笑如此拼rp的算法。
原本以为treap的random已经有点让人担心了,模拟退火则是实实在在的random了一把。
简要介绍一下这个会被我们认为是纯搞笑的算法:
模拟退火算法改进于登山算法。
登山算法是指对于初始解,随机得到与它相近的解,如果更优则选择它,如此就会很快收敛。
登山算法很容易陷入局部最优解,为了改进,我们假定,在随机过程中,一定几率会接受更差值,以摆脱局部最优解。
随机接受更差解的概率用一个“温度值”模拟,温度越高,接受概率越大。温度值会随算法的进行而降低,降低的速度是递减的。
这很类似于退火过程中,温度的减低速度随温度的降低而降低,温度越高,分子热运动和状态不稳定性越高。于是这个随机算法有了这个高深的名字。
对这个算法的能力感到怀疑,没有去编经典的旅行商问题,而是打了个小怪兽。
求f(x,y)=100sin(x*y)+sqr(x)+sqr(y)的最小值:
program lmd_Simulatedannealing; uses math; var x,y,mint,low,t,xx,yy,mayx,mayy,de:extended; function f(x,y:extended):extended; begin exit(1000*sin(x*y)+x*x+y*y); end; procedure better; begin if f(x,y)<f(mayx,mayy) then begin mayx:=x; mayy:=y; end; end; begin assign(output,'ans.out'); rewrite(output); randomize; x:=0;y:=0;low:=0.9999; mint:=1; t:=5513142647; while t>mint do begin xx:=x+(random(10)-5)/10000; yy:=y+(random(10)-5)/10000; de:=-(f(xx,yy)-f(x,y)); if t<2 then t:=t; if de>=0 then begin x:=xx; y:=yy; end else begin if exp(de/t)*1000000>random(1000000) then begin better; x:=xx;y:=yy; end; end; t:=t*low; end; if f(x,y)<f(mayx,mayy) then begin writeln(x:0:8); writeln(y:0:8); write(f(x,y):0:8); end else begin writeln(mayx:0:8); writeln(mayy:0:8); writeln(f(mayx,mayy):0:8); end; close(output); end.
发现算法的能力与数据也有很大关系,较优值很集中时,误差很大。较优值比较分散时效果还可以。
经检验,上面程序的结果在-990至-991之间移动,而枚举得到最小值在-996至-997之间,误差在1%以内,
但是如果函数改成了f(x,y)=5sin(x*y)+sqr(x)+sqr(y)的话,误差就不是一般的大了。(当然这个random可能也弱了点);
在此赞叹有有神牛用模拟退火搞定了hnoi2011的任务调度,平心而论,不仅需要能力,还需要rp支持。
ps:总而言之,这算法很rp,很无语,很搞笑。顺便看了遗传算法,感觉好一点,但是仍然rp,无语,搞笑……