参考:https://blog.csdn.net/niiick/article/details/82708589
参考:https://blog.csdn.net/m0_37579232/article/details/85057190
爬山算法
比如我要求一个函数在区间的最大值,
我开始会在这个区间内随机选几个点,然后挑最大的,
接下来在最大的点的附近又开始随机选几个点,然后再挑最大的
以此循环,最终是可以找到满足精度要求的
盘山算法实际上就是贪心,所以它满足局部最优解,但不一定满足全局最优解
我们想要的最终答案是A
爬山算法最终可能会得到B
模拟退火
为了解决爬山算法的不足
模拟退火会以一定概率接受一个非更优解
假如当前记录的最优解为B
随机到的下一个点为C
爬山算法会直接否定了这个点,但模拟退火决定以一定概率去接受
这样得到最终全局最优解A的概率就大大增加
模拟算法的描述是这样的:
若移动后得到更优解,则总是接受该移动
若移动后的解比当前解要差,则以一定的概率接受移动,而且这个概率随着时间推移逐渐降低。
这里的一定的概率的计算参考了金属冶炼的退火过程,这也是模拟退火算法名称的由来。
在
温
度
为
T
的
情
况
下
出
现
一
次
能
量
差
为
Δ
E
的
降
温
的
概
率
为
在温度为T的情况下出现一次能量差为ΔE的降温的概率为
在温度为T的情况下出现一次能量差为ΔE的降温的概率为
P
(
d
E
)
=
e
x
p
(
d
E
/
(
k
T
)
)
P(dE) = exp( dE/(kT) )
P(dE)=exp(dE/(kT))
说白了就是:温度越高,出现一次能量差为dE的降温的概率就越大;温度越低,则出现降温的概率就越小。又由于dE总是小于0(否则就不叫退火了),因此dE/kT < 0 ,所以P(dE)的函数取值范围是(0,1) 。
随
着
温
度
T
的
降
低
,
P
(
d
E
)
会
逐
渐
降
低
。
随着温度T的降低,P(dE)会逐渐降低。
随着温度T的降低,P(dE)会逐渐降低。
例题
Strange fuction
题意:
F
(
x
)
=
6
∗
x
7
+
8
∗
x
6
+
7
∗
x
3
+
5
∗
x
2
−
y
∗
x
(
0
<
=
x
<
=
100
)
F(x) = 6 * x^7+8*x^6+7*x^3+5*x^2-y*x (0 <= x <=100)
F(x)=6∗x7+8∗x6+7∗x3+5∗x2−y∗x(0<=x<=100)
给
你
y
让
你
求
m
i
n
F
(
x
)
给你y 让你求min F(x)
给你y让你求minF(x)
AC code
/*
Strange fuction
HDU - 2899
https://cn.vjudge.net/problem/HDU-2899
题意: F(x) = 6 * x^7+8*x^6+7*x^3+5*x^2-y*x (0 <= x <=100) 给你y求最小值
解法 模拟退火
*/
#include <bits/stdc++.h>
using namespace std;
#define T 100.0
#define delta 0.999
#define eps 1e-8
double y,dx[2]={1.0,-1.0};
double F(double x){
return 6.0*pow(x,7.0)+8.0*pow(x,6.0)+7.0*pow(x,3)+5.0*pow(x,2.0)-y*x;
}
int main(){
int Q;
cin>>Q;
while(Q--){
cin>>y;
double t=T,x=100.0,ans=F(x);
while(t>eps){
double nx=-1.0;
while(nx<0||nx>100) nx=x+dx[rand()%2]*t;
double de=ans-F(nx);
if(de>=0) x=nx,ans=F(nx);
else if(exp(de/t)>(double)rand()/(double)RAND_MAX) x=nx;
t*=delta;
}
printf("%.4lf\n", ans);
}
return 0;
}
/*
Strange fuction
HDU - 2899
https://cn.vjudge.net/problem/HDU-2899
题意: F(x) = 6 * x^7+8*x^6+7*x^3+5*x^2-y*x (0 <= x <=100) 给你y,求F(x)最小值
解法: 爬山算法
*/
#include <bits/stdc++.h>
using namespace std;
#define T 100.0
#define delta 0.999
#define eps 1e-8
double y,dx[2]={1.0,-1.0};
double F(double x){
return 6.0*pow(x,7.0)+8.0*pow(x,6.0)+7.0*pow(x,3)+5.0*pow(x,2.0)-y*x;
}
int main(){
int Q;
cin>>Q;
while(Q--){
cin>>y;
double t=T,x=100.0,ans=F(x);
while(t>eps)
{
double nx=-1.0;
while(nx<0||nx>100) nx=x+dx[rand()%2]*t;
if(F(nx)<F(x)) x=nx;
t*=delta;
}
printf("%.4lf\n",F(x));
}
return 0;
}