模拟退火算法源于金属退火的原理。当固体温度很高时,内能较大,内部粒子进行快速的无序运动,当温度逐渐降低时,粒子运动速度逐渐下降,逐渐趋于有序,也基本趋于稳定。
在搜索全局最优解时,我们也可以先设置一个高温,然后逐渐降低温度,直到温度趋近于0。在冷却过程中,对于每个温度,都去迭代多次,来寻找局部最优解:
温度趋近于0时,算法结束,即可得出最终的答案。
为什么要有概率跳出而不是不跳出呢?因为如果现在找到了一个局部最优解,虽然它不是全局最优解,但如果在一定范围内没有比它更优的解,那最后的结果就是这个局部最优解了。如果有一定的概率能跳出,则就有可能找到另一个局部最优解。最后取所有局部最优解的最优解,得出的结果有更大概率是全局最优解。
模拟退火算法是一个近似算法,它并不能保证找到的结果是全局最优解。
其中跳出的概率 P P P满足以下公式(假设函数值最小为最优):
P
=
{
1
f
(
x
′
)
≤
f
(
x
)
e
f
(
x
)
−
f
(
x
′
)
k
T
f
(
x
′
)
>
f
(
x
)
P=\left\{
其中 T T T表示初始温度, k k k表示温度下降的速率。
可以看出,当温度越⾼时,越有可能跳出局部最优解;当温度越⼩时,越趋向于稳定,越不容易跳出局部最优解。
在温度固定的情况下,模拟退⽕算法需要迭代多次,迭代的次数越多,越容易找到局部最优解。这个迭代次数称为⻢尔科夫链。
但⻢尔科夫链越⻓,所需要的时间也越多。
题目大意:定义函数 f ( x ) = 6 x 7 + 8 x 6 + 7 x 3 + 5 x 2 + a x f(x)=6x^7+8x^6+7x^3+5x^2+ax f(x)=6x7+8x6+7x3+5x2+ax, a a a已知。求当 0 ≤ x ≤ 100 0\leq x\leq 100 0≤x≤100时 f ( x ) f(x) f(x)的最小值。保留四位小数。有多组数据。
用模拟退火算法搜索 x x x。对于每个温度,求局部最优解。最后比较局部最优解,就能得出最后的结果。
#include
#include
#include
#include
#include
using namespace std;
int tt,T=50;
double a,t0=100,t1,t2=1e-8,k=0.98;
double f(double x){
return 6*x*x*x*x*x*x*x+8*x*x*x*x*x*x+7*x*x*x+5*x*x-a*x;
}
double rd(double x){
return rand()*1.0/RAND_MAX*x;
}
int main()
{
srand(time(NULL));
double x,y,tx,ty,px,py;
scanf("%d",&tt);
while(tt--){
scanf("%lf",&a);
t1=t0;
x=0;
px=0;py=f(0);
while(t1>t2){
y=f(x);
for(int i=1;i<=T;i++){
tx=x+(rand()%2*2-1)*t1;
if(tx<-0.01||tx>100.01) continue;
ty=f(tx);
if(ty<y){
x=tx;y=ty;
}
else{
if(rd(1)<exp((y-ty)/t1)){
x=tx;y=ty;
}
}
if(ty<py){
px=tx;py=ty;
}
}
t1=t1*k;
}
if(px<0.0) px=0.0;
if(px>100.0) px=100.0;
printf("%.4f\n",f(px));
}
return 0;
}