什么是模拟退火:
模拟退火(Simulated Annealing,简称SA)是一种通用 概率算法,用来在一个大的搜寻空间内找寻 命题的 最优解。
“模拟退火”来自冶金学的专有名词淬火
“模拟退火”的原理也和金属退火的原理近似:我们将热力学的理论套用到统计学上,将搜寻空间内每一点想像成空气内的分子;分子的能量,就是它本身的动能;而搜寻空间内的每一点,也像空气分子一样带有“能量”,以表示该点对命题的合适程度。算法先以搜寻空间内一个任意点作起始:每一部先选择一个“邻居”,然后再计算从现有位置到达“邻居”的概率。
模拟退火算法可以分解为解空间、目标函数和初始解三部分。
模拟退火的基本思想:
(1) 初始化:初始温度T(充分大),初始解状态S(是算法迭代的起点), 每个T值的迭代次数L
(2) 对k=1,……,L做第(3)至第6步:
(3) 产生新解S′
(4) 计算增量Δt′=C(S′)-C(S),其中C(S)为评价函数
(5) 若Δt′<0则接受S′作为新的当前解,否则以概率exp(-Δt′/T)接受S′作为新的当前解.
(6) 如果满足终止条件则输出当前解作为最优解,结束程序。
终止条件通常取为连续若干个新解都没有被接受时终止算法。
(7) T逐渐减少,且T->0,然后转第2步。
算法对应动态演示图:
模拟退火算法新解的产生和接受可分为如下四个步骤:
第一步是由一个产生函数从当前解产生一个位于解空间的新解;为便于后续的计算和接受,减少算法耗时,通常选择由当前新解经过简单地变换即可产生新解的方法,如对构成新解的全部或部分元素进行置换、互换等,注意到产生新解的变换方法决定了当前新解的邻域结构,因而对冷却进度表的选取有一定的影响。
第二步是计算与新解所对应的目标函数差。因为目标函数差仅由变换部分产生,所以目标函数差的计算最好按增量计算。事实表明,对大多数应用而言,这是计算目标函数差的最快方法。
第三步是判断新解是否被接受,判断的依据是一个接受准则,最常用的接受准则是Metropo1is准则: 若Δt′<0则接受S′作为新的当前解S,否则以概率exp(-Δt′/T)接受S′作为新的当前解S。
第四步是当新解被确定接受时,用新解代替当前解,这只需将当前解中对应于产生新解时的变换部分予以实现,同时修正目标函数值即可。此时,当前解实现了一次迭代。可在此基础上开始下一轮试验。而当新解被判定为舍弃时,则在原当前解的基础上继续下一轮试验。
模拟退火算法与初始值无关,算法求得的解与初始解状态S(是算法迭代的起点)无关;模拟退火算法具有渐近收敛性,已在理论上被证明是一种以概率l 收敛于全局最优解的全局优化算法;模拟退火算法具有并行性。
(以上来自搜狗百科,个人觉得纯粹是在扯皮,身为OI选手我觉得我们还是务实点好)
模拟退火,其实就是在达到一个局部最优解的情况下有一定的概率改变当下的情况先取到一个较差的情况,之后再找一个局部最优解。不断重复以上过程,当然若是始终找不到更优解的话要有一个适当的时机停止,我们此时认为当前最优解就是全局最优解。
有没有什么经典的例子呢?
个人认为,下面这个题目就很不错
题目描述
Time Limit: 1000MS | Memory Limit: 65536K | |||
Total Submissions: 6160 | Accepted: 1545 | Special Judge |
Description
According to this theory, starts we are observing are not independent objects, but only small portions of larger objects called super stars. A super star is filled with invisible (or transparent) material, and only a number of points inside or on its surface shine. These points are observed as stars by us.
In order to verify this theory, Dr. Extreme wants to build motion equations of super stars and to compare the solutions of these equations with observed movements of stars. As the first step, he assumes that a super star is sphere-shaped, and has the smallest possible radius such that the sphere contains all given stars in or on it. This assumption makes it possible to estimate the volume of a super star, and thus its mass (the density of the invisible material is known).
You are asked to help Dr. Extreme by writing a program which, given the locations of a number of stars, finds the smallest sphere containing all of them in or on it. In this computation, you should ignore the sizes of stars. In other words, a star should be regarded as a point. You may assume the universe is a Euclidean space.
Input
n
x1 y1 z1
x2 y2 z2
. . .
xn yn zn
The first line of a data set contains an integer n, which is the number of points. It satisfies the condition 4 <= n <= 30.
The location of n points are given by three-dimensional orthogonal coordinates: (xi, yi, zi) (i = 1, ..., n). Three coordinates of a point appear in a line, separated by a space character. Each value is given by a decimal fraction, and is between 0.0 and 100.0 (both ends inclusive). Points are at least 0.01 distant from each other.
The end of the input is indicated by a line containing a zero.
Output
Sample Input
4 10.00000 10.00000 10.00000 20.00000 10.00000 10.00000 20.00000 20.00000 10.00000 10.00000 20.00000 10.00000 4 10.00000 10.00000 10.00000 10.00000 50.00000 50.00000 50.00000 10.00000 50.00000 50.00000 50.00000 10.00000 0
题目含义:对于给定多个三维坐标,找出半径最小的可以包含它们全部的球并且输出半径长
是不是有人想到高斯消元?......反正我没有试过,也懒得去推,也许可以吧,我不知道。毕竟这里是模拟退火的小结。
那么我们考虑怎么退火呢?首先我们确定一个点,就是所有点坐标的平均吧(我瞎取的)。然后明确当前点的最小半径是到它最远点的距离。
设定一个不断减小的概率delta,然后不断逼近离自己最远的点,可以发现坐标会逐渐收敛。值得注意的是,坐标变化幅度不应太大,而且要
逐渐减小,如果过不了样例的话就随便改改,虽然不确定能不能A,但模拟退火本来就是骗分技巧,而且高明的退火总是取得非常优异的效果。
最后直接输出ans就好。
对于这一种坐标式的,关键在于不断逼近答案并收敛。
下面是我的poj AC代码
#include<bits/stdc++.h> using namespace std; const int maxn=30+5; const double inf=1e9+7; double dist(double x1,double y1,double z1,double x2,double y2,double z2) { return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2)); } int main() { int t; while (1) { scanf("%d",&t); if (t==0) break; double ansx,ansy,ansz; double x[maxn],y[maxn],z[maxn]; for (int i=1;i<=t;i++) { scanf("%lf%lf%lf",x+i,y+i,z+i); ansx+=x[i]; ansy+=y[i]; ansz+=z[i]; } ansx=ansx/t;ansy=ansy/t;ansz=ansz/t; double delta=100.0;double ans=inf; while (delta>0.0000001) { int d=1; for (int i=2;i<=t;i++) { if (dist(x[d],y[d],z[d],ansx,ansy,ansz)<dist(x[i],y[i],z[i],ansx,ansy,ansz)) d=i; } double now=dist(x[d],y[d],z[d],ansx,ansy,ansz); ans=min(ans,now); ansx+=(x[d]-ansx)/now*delta; ansy+=(y[d]-ansy)/now*delta; ansz+=(z[d]-ansz)/now*delta; delta*=0.97; } printf("%.5lf ",ans); } return 0; }
其实洛谷上也有模拟退火的好题,推荐大家去找找,我忘记题号了。下面留一个大佬整理的模拟退火题目的链接给大家https://blog.csdn.net/HHYULARHH/article/details/10343957