• 模拟退火算法


    算法由来

    对于一个非晶体的固体,
    我们可以通过将其加热到某一温度,使得其分子活化,
    在徐徐降温,使其分子排布趋向有序。
    我们也可以通过模拟固体降温的过程,不断的靠向最优值。

    用途

    这是一个用于求解一些最优化问题的随机算法。

    算法流程

    首先,因为这是一个随机算法,为了保险,我们多做几次。
    下面我们只考虑某一次的算法过程:

    • 我们先选定一个初值(初始的答案)(Ans_0)
    • 我们再选定一个初始的温度(T)和每次的降温幅度(D)
    • 我们考虑每一次降温之后,生成一个新解,

    对于生成一个新解,我们不太可能直接在可行域中随机,这显然不太科学。
    我们只考虑当前解关于温度(T)的“邻域”,即变化范围和(T)正相关。
    这也是模拟退火温度越低,越稳定的原因之一。

    • 一般上都是从当前解通过一些简单变换得到新解(Ans_1)

    此时,我们考虑设计一个估价函数(f(x))表示将(x)作为答案的优劣程度,
    习惯上(f(x))越大,(x)作为答案越不优秀。

    • 有了估价函数,我们就可以考虑是否接受新解了:

      1. 如果(f(Ans_1) < f(Ans_2)),那么直接接受。
      2. 如果(f(Ans_1) > f(Ans_2)),此时我们需要一定概率的接受劣解,
        借此“跳出”局部最优解,达到全局最优解,具体如下:

        根据(Metropolis)准则,粒子在温度(T)时趋于平衡的概率为(exp(-Delta E/(kT)))
        其中(Delta E)为当前解与新解之间的“内能差”,(k)(Boltzmann)常数,当作(1)就好,
        那么,我们生成一个劣解之后,就有(exp(-frac{f(Ans_1)-f(Ans_2)}{T}))的概率接受它了。
        这就是温度(T)越低,接受劣解的概率越小,越稳定。

    • 最后我们设置一个温度下限,当温度达到这个值之后就输出答案。

    • 那么我们就可以求出近似最优解了。

    模板代码((HDU2899))

    #include <bits/stdc++.h>  
      
    using namespace std;
    
    typedef double db;
    
    db Y;
    db func(db x, db res = 0.0) {
      res += 5.0 * x * x;
      res += 7.0 * x * x * x;
      res += 8.0 * x * x * x * x * x * x;
      res += 6.0 * x * x * x * x * x * x * x;
      return res - Y * x;
    }
    
    const db lim = RAND_MAX;
    db P() { return (db)(rand()) / lim; }
    db Sgn[2] = {1, -1};
    db Delta(db T) { return Sgn[rand() & 1] * T * P(); }
    
    const db eps = 1e-10, D = 0.95;
    db calc() {
      db Ans_0 = P() * 100.0, F_0 = func(Ans_0);
      for(db T = 101.0; T > eps; T *= D) {
        db Ans_1 = Ans_0 + Delta(T), F_1 = func(Ans_1);
        if(Ans_1 < 0.0 || Ans_1 > 100.0) continue;
        if(F_1 < F_0 || P() < exp((F_0 - F_1) / T)) Ans_0 = Ans_1, F_0 = F_1;
      }
      return Ans_0;
    }
    
    int main() {
      srand(time(0));
      int T = 0;
      scanf("%d", &T);
      while(T--) {
        scanf("%lf", &Y);
        db Ans = 1e15;
        for(int i = 1; i <= 100; i++)
          Ans = min(Ans, func(calc()));
        printf("%.4lf
    ", Ans);
      }
      return 0;
    }
    
  • 相关阅读:
    没有服务商如何购买ERP的序列号?
    智能ERP主副机设置
    银盒子·序列号购买(2018-12-05)
    简易付微信收款提示支付失败
    简易付无法登录的解决方案
    Orchard详解--第八篇 拓展模块及引用的预处理
    Orchard详解--第七篇 拓展模块(译)
    Orchard详解--第六篇 CacheManager 2
    Orchard详解--第五篇 CacheManager
    Orchard详解--第四篇 缓存介绍
  • 原文地址:https://www.cnblogs.com/tacmon52818/p/12713168.html
Copyright © 2020-2023  润新知