草庐IT

模拟退火学习笔记

reasa 2023-03-28 原文

1.简介

模拟退火算法来源于固体退火原理,是一种基于概率的算法,将固体加温至充分高,再让其徐徐冷却,加温时,固体内部粒子温升变为无序状,内能增大,而徐徐冷却时粒子渐趋有序,在每个温度都达到平衡态,最后在常温时达到基态,内能减为最小。     ————百度百科

简而言之,模拟退火是一种随机化算法,常用于信息学竞赛中骗取高分,但因为其为随机化算法,所以不是很稳定,少则10分,多则AC,这取决于你的RP了(doge)。 它与爬山算法最大的不同是,在寻找到一个局部最优解时,赋予了它一个跳出去的概率,也就有更大的机会能找到全局最优解。

2.原理

原理在这里就不过多说了,因为可能对于程序的编写没有多大的影响,下面直接给出百度百科的原理介绍:

模拟退火的原理也和金属退火的原理近似:将热力学的理论套用到统计学上,将搜寻空间内每一点想像成空气内的分子;分子的能量,就是它本身的动能;而搜寻空间内的每一点,也像空气分子一样带有“能量”,以表示该点对命题的合适程度。演算法先以搜寻空间内一个任意点作起始:每一步先选择一个“邻居”,然后再计算从现有位置到达“邻居”的概率。

 简单来说就是,随机生成一个新的解,然后将其与先前的最优解进行比较,若生成的新解更优,则更新最优解,否则以exp(-ΔT/T)的概率接受它,exp是计算以自然底数为底的指数的函数,而这里的接受并不是指将新解作为最优解,而是更新步骤。

3.过程

  1)降温

    模拟退火有三个重要的参数,分别为初温t、降温系数ΔT和终温Tk,这三个参数关系到你的程序结果的准确性,当然,如何选择恰当的参数需要你的经验和RP了。其中,t是一个比较大的数,ΔT 是一个略小于 1 的正数,Tk 是一个略大于 0 的正数。我们先设当前温度T为初温,然后每次降温时 T 乘上 ΔT,直到 T≤Tk 为止

    大致过程如下:

              

    可以看出,随着温度的降低,解逐渐稳定下来,并逐渐集中在最优解附近。

  2)生成新解

    生成新解的基本思想就是使用rand随机生成一个值,并带入对应的计算函数就可以得出一个新解了,而计算函数是根据对应题目来决定的,往往都不相同。

  3)调参

    这可能是模拟退火中最重要的一步了,一个好的参数可一让你AC你所作的题,而一个坏的参数,可能让你的分数比暴力还低,一般来讲,如果答案不是最优,有以下几种调法:调大ΔT,调整t和Tk或多跑即便退火,如果太非的话,这边还是建议您直接打正解吧(

  4)调整

    如果新解更优,接受这个解。否则我们以一定概率接受这个解。设ΔW为新解和当前解的差 ΔW>0 。我们希望的是:T越大时概率越大,ΔW越小时概率越小。个随机数。当然,如果 ΔW很大或很小的话这样子就可能会出问题。我们可以通过合理选择r的范围来解决问题。

  5)其他

    模拟退火中,还有一件重要的事就是选好随机数种子,和调参一样,种子选好了收益整个比赛,种子太臭,像11451419就会出事,下面是我的惨痛教训

 

    

 

    

    程序开始时,我们要先srand(一个常数)。这个常数可以决定分数。你可以使用 233333,2147483647,甚至某个八位质数

    可以用一个全局变量记录所有跑过的模拟退火的最优解,每次从那个最优解开始继续模拟退火,可以减小误差。

4.实际应用

  这里以洛谷1337 [JSOI2004]平衡点 / 吊打XXX为例,讲解模拟退火的实际应用。

  题目要使整个系统的能量最小。那么我们只要用模拟退火跑出这个最小值即可。

  代码如下:

#include <bits/stdc++.h>
#define re register 
using namespace std;
inline int read() {
    int X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=(X<<3)+(X<<1)+c-'0',c=getchar();
    return X*w;
}
int n,sx,sy;
double ansx,ansy; //全局最优解坐标 
double ans = 1e18,t; //全局最优解,温度t
const double delta = 0.9913;
struct node{
    int x,y,w;
}a[1010];
inline double calc_energy(double x,double y){
    double rt=0;
    for (re int i=1;i<=n;i++) {
        double deltax=x-a[i].x,deltay=y-a[i].y;
        rt+=sqrt(deltax*deltax+deltay*deltay)*a[i].w;
    }
    return rt;
}
inline void simulate_anneal(){
    double x = ansx,y = ansy;
    t = 2000; //设初温
    while (t>1e-14){
        double X = x+((rand()<<1)-RAND_MAX)*t;
        double Y = y+((rand()<<1)-RAND_MAX)*t;
        double now = calc_energy(X,Y);
        double Delta = now-ans; //当前最优解与新解的差
        if (Delta<0){
            x = X;
            y = Y;
            ansx = x,ansy = y,ans = now;
        } 
        else if (exp(-Delta/t)*RAND_MAX>rand()){ //若不是当前最优,则有一定概率接受它 
            x = X;
            y = Y;
        }
        t*=delta;
    }
}
inline void Solve() { //多跑几遍模拟退火,减小误差
    ansx=(double)sx/n,ansy=(double)sy/n; //从平均值开始更容易接近最优解
    simulate_anneal();
    simulate_anneal();
    simulate_anneal();
}
int main(){
    srand(11451411919); srand(rand()); srand(rand());
    n = read();
    for (re int i=1;i<=n;i++){
        a[i].x = read(),a[i].y = read(),a[i].w = read();
        sx+=a[i].x,sy+=a[i].y;
    }
    Solve();
    printf("%.3f %.3f\n",ansx,ansy);
    return 0;
}

 

Over~

有关模拟退火学习笔记的更多相关文章

  1. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  2. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  3. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  4. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  5. ruby-on-rails - 在这种情况下我如何模拟一个对象?没有明显的方法可以用模拟替换对象 - 2

    假设我在Store的模型中有这个非常简单的方法:defgeocode_addressloc=Store.geocode(address)self.lat=loc.latself.lng=loc.lngend如果我想编写一些不受地理编码服务影响的测试脚本,这些脚本可能已关闭、有限制或取决于我的互联网连接,我该如何模拟地理编码服务?如果我可以将地理编码对象传递到该方法中,那将很容易,但我不知道在这种情况下该怎么做。谢谢!特里斯坦 最佳答案 使用内置模拟和stub的rspecs,你可以做这样的事情:setupdo@subject=MyCl

  6. ruby - 我正在学习编程并选择了 Ruby。我应该升级到 Ruby 1.9 吗? - 2

    我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or

  7. ruby - "public/protected/private"方法是如何实现的,我该如何模拟它? - 2

    在ruby中,你可以这样做:classThingpublicdeff1puts"f1"endprivatedeff2puts"f2"endpublicdeff3puts"f3"endprivatedeff4puts"f4"endend现在f1和f3是公共(public)的,f2和f4是私有(private)的。内部发生了什么,允许您调用一个类方法,然后更改方法定义?我怎样才能实现相同的功能(表面上是创建我自己的java之类的注释)例如...classThingfundeff1puts"hey"endnotfundeff2puts"hey"endendfun和notfun将更改以下函数定

  8. ruby - 在 RSpec 中 stub /模拟全局常量 - 2

    我有一个gem,它有一个根据Rails.env的不同行为的方法:defself.envifdefined?(Rails)Rails.envelsif...现在我想编写一个规范来测试这个代码路径。目前我是这样做的:Kernel.const_set(:Rails,nil)Rails.should_receive(:env).and_return('production')...没关系,只是感觉很丑。另一种方法是在spec_helper中声明:moduleRails;end而且效果也很好。但也许有更好的方法?理想情况下,这应该有效:rails=double('Rails')rails.sho

  9. ruby - 我如何学习 ruby​​ 的正则表达式? - 2

    如何学习ruby​​的正则表达式?(对于假人) 最佳答案 http://www.rubular.com/在Ruby中使用正则表达式时是一个很棒的工具,因为它可以立即将结果可视化。 关于ruby-我如何学习ruby​​的正则表达式?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1881231/

  10. ruby-on-rails - rspec 模拟对象属性赋值 - 2

    我有一个rspec模拟对象,一个值赋给了属性。我正在努力在我的rspec测试中满足这种期望。只是想知道语法是什么?代码:defcreate@new_campaign=AdCampaign.new(params[:new_campaign])@new_campaign.creationDate="#{Time.now.year}/#{Time.now.mon}/#{Time.now.day}"if@new_campaign.saveflash[:status]="Success"elseflash[:status]="Failed"endend测试it"shouldabletocreat

随机推荐