模拟退火(SA)详解

SA——优雅的暴力

  1. 随机出一个答案:根据题目而变,但一般是随机出的,但是和简单的随机不同,这个答案一般是根据先有的解(注意,不一定是最优解,因为有一定概率我们接受了一个可能更接近最优答案的答案),在此基础随机出的

  2. 确定接受新状态的概率:见下面代码

模拟退火算法进阶

  1. 关于参数

模拟退火的参数基本上决定了代码的准确性,一般的, T0 越高, Tk 越低( Tk>0 ),d 越接近 1 ,模拟退火越准确, 但时间越长,建议在写模拟退火是要卡卡参数

  1. 关于随机数

模拟退火的精髓就在随机数上,随机数的随机性,循环周期基本上决定了准确度,随机性差,循环周期短的很可能将模拟退火卡掉,建议参考这来优化随机数

  1. 关于时间

    模拟退火是一个不太稳定的算法 (谁叫他随机),单次可能找不到最优解,一般的要多次运行,有一个 clock() 函数,返回程序运行时间,建议在不超时的情况下尽可能多跑

    一般的,可以这样while((double)clock()/CLOCKS_PER_SEC<=0.8) SA();(进行模拟退火);

  2. 关于随机化种子

    srand((unsigned)time(0)) or srand((int)time(NULL))
    
  3. 关于概率接受劣解概率

    EP(E)={1eETotherwise

模板快餐

void SA()
{
	double T = 2000;//初始温度
	while(T > 1e-10)//退出温度
	{
      	随机生成一个新解
		T *= 0.987;//降温
		double delta = 原解 - 新解;
		if(更优||exp(-(double)delta*RAND_MAX/T) < rand())
        /*
        关于概率接受劣解的判断条件
        exp(-Delta/t)*RAND_MAX<rand() ->> 最大值
        exp(-Delta/t)*RAND_MAX>rand() ->> 最小值
        */
		{
			res = new_res;//接受/一定概率接受
		}
	}
	ans = min(ans,res);//去最值(或其他)
}

最后一点

SA时间复杂度:O(F×(logdeltaT0/Tmin))

写题经验

  • 求一个坐标,使其 最大/小

    这样退火:
    double tx=sx+(rand()*2-RAND_MAX)*T;
    double ty=sy+(rand()*2-RAND_MAX)*T;
    
  • 交换顺序,使其 最大/小

    这样退火:
    int x=rand()%n+1;
    int y=rand()%n+1;
    swap(a[x],a[y]);
    
  • NOIP2021方差,这个比较特殊(退火能拿满分)。

posted @   tyccyt  阅读(104)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
点击右上角即可分享
微信分享提示