模拟退火

模拟退火

问题引入

n个有k维性质以及价值w的物品,放入m个有k维限制的背包中,求总价值最大值

爬山&贪心

这题有一个显而易见的错误做法,先把物品按某种神秘方式排序,然后贪心地放入背包

于是考虑乱搞,每次random_shuffle一下物品,再重新计算,取历史最优解,正确率就得到提高了,但期望得到正解的次数是n!级别的,和暴力没有区别

考虑优化,发现这是因为没有利用之前贪心得到的一些优秀特征,比如有一个没有代价的物品被移来移去就是毫无意义的

由此可以发现,应当减少每次移动的数量,把random_shuffle变成swap,这样效率没有改变,但是按神秘方式排序后得到正确结果的概率提高了,耗费在移动上的时间也减少了

模拟退火

随贪乱搞显然是不行的,必须继续优化,发现随机swap依然可能导致优秀特征的随机损失或无效的交换

为了避免这一问题,模拟退火以一定概率接受随机的修改

分两种情况考虑:

新解优于历史最优解:当然接受这次修改

新解不优于历史最优解:以eΔfT的概率接受新解

Δf表示新解与历史最优解的差,T是模拟退火的一个可变参数,具体地,

Tnexttime=Tnowδ

δ是一个常数,取值通常在[0.98,1],用来更新T,也就是当前温度

这样比完全随机接受优是因为Δf表明答案劣化的越少越容易接受,T的设置则使得接受新解的概率越来越小,使得算法越来越接近朴素爬山

名字叫模拟退火是因为从物理上固体退火得到的启发

模板:

calc();//计算新解
renew();//随机刷新
recover();//还原刷新
SA()
{
    auto tmp;
    double T=;
    while(T>=eps)
    {
        renew();
        tmp=calc();//临时答案
        if(better(tmp,ans)) ans=tmp;//如果更优
        else if(exp((tmp-ans)/T)*RAND_MAX<=rand()) recover();//有可能接受
        T*=delta;//刷新温度
    }
}

while(clock()<=CLOCKS_PER_SEC*MAX_TIME) SA();//卡时调用,MAX_TIME比题目时限小一点

解释一下

eΔfTRANDMAXrand()eΔfT0.5

就可以做到随机接受了

posted @   嘉年华_efX  阅读(82)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示

目录导航