爬山算法 x 模拟退火

爬山算法(Hill Climbing)

学习模拟退火前了解爬山算法是非常必要的

爬山算法依照一个很简单的贪心思路
每次在当前作为最优解的点附近随机一个新的点
比较这个新的点是否比当前更优,若是则更新

这个算法有一个比较明显的缺点,例如下图

我们想要的最终答案是A
但若当前记录的最优解是B
局部最优解B附近谷底的点又显然不能作为更优解更新答案

所以爬山算法最终得到的将有可能只是局部最优解
爬山算法 x 模拟退火_第1张图片


模拟退火(SA——Simulated Annealing)

为了解决上述爬山算法的不足
模拟退火算法应用了以一定概率接受一个非更优解的思路

加入当前记录的最优解为B
随机到的下一个点为C
爬山算法直接否定了这个点,但模拟退火决定以一定概率去接受
这样得到最终全局最优解A的概率就大大增加
爬山算法 x 模拟退火_第2张图片

关于如何确定接受概率,就应用到了金属退火原理

在温度为 T T T的情况下
出现一次能量差为 Δ E \Delta E ΔE的降温的概率为 P ( Δ E ) = e Δ E k ∗ T P(\Delta E)=e^{\frac{\Delta E}{k*T}} P(ΔE)=ekTΔE

这个要如何应用到OI中呢
我们设定一个初始温度 T 0 T_0 T0最小温度 T m i n T_{min} Tmin,以及降温系数 d e l t a delta delta
每次降温就是令 T ∗ = d e l t a T*=delta T=delta
温度下降到 T m i n T_{min} Tmin时算法结束

假设在温度 T T T时记录的最优解为 F ( x ) F(x) F(x)
随机一个 x x x附近的点 x 1 x_1 x1并计算他的函数值 F ( x 1 ) F(x_1) F(x1)
他们的差作为退火的能量差,即 Δ E = F ( x 1 ) − F ( x ) \Delta E=F(x_1)-F(x) ΔE=F(x1)F(x)
Δ E > = 0 \Delta E>=0 ΔE>=0,说明这个新的点更优,直接更新
Δ E < 0 \Delta E<0 ΔE<0,我们就 P ( Δ E ) P(\Delta E) P(ΔE)的概率接受这个非更优解

因为 Δ E < 0 \Delta E<0 ΔE<0,所以 P ( Δ E ) P(\Delta E) P(ΔE)的取值范围是 ( 0 , 1 ) (0,1) (0,1)
显然温度 T T T越小接受的概率也越小

爬山算法:兔子朝着比现在高的地方跳去。它找到了不远处的最高山峰。但是这座山不一定是珠穆朗玛峰。这就是爬山算法,它不能保证局部最优值就是全局最优值。

模拟退火:兔子喝醉了。它随机地跳了很长时间。这期间,它可能走向高处,也可能踏入平地。但是,它渐渐清醒了并朝最高方向跳去。这就是模拟退火。

下面给出模拟退火伪代码

/*
F(x)在状态x时的评价函数值
x , nx 当前状态 与 新的状态 
delta: 用于控制降温的快慢
T: 系统的温度,系统初始应该要处于一个高温的状态
T_0 , T_min :初始温度 与 温度的下限,当温度T从T_0降温到T_min,算法结束
*/
T=T_0
while(T>T_min)
{
  nx=RADN(x);//在当前状态x附近随机一个新的状态 
	dE=F(nx)-F(x); //能量差 

  if(dE>=0) x=nx;//直接接受更优的移动 
  else if( exp( dE/T ) > random(0,1) ) x=nx;//以一定概率接受非更优的移动 
	//(exp是c++库函数) exp( dE/T )随温度降低而减小 

  T=T*delta; //降温退火 ,0

	//delta越大,降温越慢, 反之delta越小,降温越快
	//若delta过大,则搜索到全局最优解的可能会较高,但搜索的过程也就较长。
	//若delta过小,则搜索的过程会很快,但最终可能会达到一个局部最优值
}

要注意接受非更优解时只是接受点的移动当前记录最优解的值不用更新


爬山算法与模拟退火的应用

HDU-2899 Strange fuction

求函数 F ( x ) = 6 ∗ x 7 + 8 ∗ x 6 + 7 ∗ x 3 + 5 ∗ x 2 − y ∗ x F(x) = 6 * x^{7} +8*x^6+7*x^3+5*x^2-y*x F(x)=6x7+8x6+7x3+5x2yx在0 <= x <=100内的最小值

//模拟退火
#include
#include
#include
#include
#include
#include
using namespace std;
typedef double dd;
#define T 100//初始温度
#define delta 0.999//降温系数
#define eps 1e-8//温度下限

int read()
{
    int x=0,f=1;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return x*f;
}

int Q;
dd y,dd dx[2]={1.0,-1.0};

dd qpow(dd a,int k){ dd res=1.0; while(k>0){ if(k&1)res*=a; a*=a; k>>=1;} return res;}
dd F(dd x){ return 6.0*qpow(x,7)+8.0*qpow(x,6)+7.0*qpow(x,3)+5.0*qpow(x,2)-y*x;}

int main()
{
    Q=read();
    while(Q--)
    {
        scanf("%lf",&y);
        
        dd t=T,x=100.0,ans=F(x);
    	while(t>eps)
    	{
        	dd nx=-1.0;
    		while(nx<0||nx>100) nx=x+dx[rand()%2]*t;
        	dd dE=ans-F(nx);
        	if(dE>=0) x=nx,ans=F(nx);
        	else if( exp(dE/t) > ((dd)rand()/(dd)RAND_MAX) ) x=nx;
        	//以一定概率接收非更优解
        	t*=delta;
    	}
        printf("%.4lf\n",ans);
    }
    return 0;
}
//爬山算法主要代码
Q=read();
while(Q--)
{
    scanf("%lf",&y); 
   	dd t=T,r=delta,x=100.0;
    	
    while(t>eps)
    {
    	dd nx=-1.0;
    	while(nx<0||nx>100) nx=x+dx[rand()%2]*t;
    	if(F(nx)<F(x)) x=nx;
    	t*=r;
	}
	printf("%.4lf\n",F(x));
}


POJ-2420 A Star not a Tree?

在坐标系内给定n个点的坐标 ,求一个点使其到这n个点距离和最小(类似于费马点)

POJ-2420 题解

POJ-2069 Super Star

在三维坐标系中给出n个点,用一个球体包含这n个点,求最小半径

POJ - 2069 题解

BZOJ2428 ||洛谷P2503[HAOI2006]均分数据

把n个数分为m组,求每组数和的最小方差

[HAOI2006]均分数据 题解

持续更新…

你可能感兴趣的:(爬山,x,退火)