• 模拟退火基础学习&模板


    模拟退火

    概述

    简单说,模拟退火是一种随机化算法,用于求函数的极值。当一个问题的方案数量极大(甚至是无穷的)而且不是一个单峰函数时,我们常使用模拟退火求解。

    它与爬山算法最大的不同是,在寻找到一个局部最优解时,赋予了它一个跳出去的概率,也就有更大的机会能找到全局最优解。

    在 OI 领域,对应的,每次随机出一个新解,如果这个解更优,则接受它,否则以一个与温度和与最优解的差相关的概率接受它。

    相关参数

    初始温度:(T_0)

    结束温度:(T_s)

    降温系数:(Delta t)

    这样每次温度就是上次的温度乘上(Delta t)

    能量差:(Delta E=f(t_{new})-f(t_{now})),即新点的能量减去当前的能量(能量也就是函数值)

    接受概率:(P(Delta E)=e^{frac{-Delta E}{t}}),t为当前温度,这样保证当能量差小于0时,概率P是大于1的,也就是必然接受,当能量差大于0时,能量差越大越不容易接受,t越大越容易接受(这里能量差需要具体问题具体分析,因为是退火,所以能量是越小越好)

    模板

    AcWing 3167. 星星还是树

    二维平面有若干点,寻找一个点到所有点的距离之和最短,该点可以选择在平面中的任意位置,甚至与这 n 个点的位置重合。

    #include <bits/stdc++.h>
    using namespace std;
    
    #define pdd pair<double, double>
    int const N = 100 + 5;
    vector<pdd> a;
    const double inf = 2e6;  
    double ans = inf;
    
    double getd(pdd x, pdd y) {
        double dx = x.first - y.first;
        double dy = x.second - y.second;
        return sqrt(dx * dx + dy * dy);
    }
    
    double getsum(pdd x) { //f函数
        double re = 0;
        for (auto& p : a) {
            re += getd(x, p);
        }
        ans = min(ans, re);
        return re;
    }
    
    double rand(double l, double r) { //计算一个l到r的随机值
        return (double)rand() / RAND_MAX * (r - l) + l;
    }
    
    void sa() {
        pdd p(rand(0, 1e4), rand(0, 1e4));
        for (double t = 1e4; t > 1e-4; t *= 0.99) {
            pdd np(rand(p.first - t, p.first + t),
                   rand(p.second - t, p.second + t));//随机一个新的点
            double dt = getsum(np) - getsum(p);  //计算能量差
            if (exp(-dt / t) > rand(0, 1)) {
                p = np;
            }
        }
    }
    
    int main() {
        int n;
        cin >> n;
        srand((unsigned)time(NULL));
        for (int i = 0; i < n; ++i) {
            double x, y;
            cin >> x >> y;
            a.push_back({x, y});
        }
        for (int i = 0; i < 100; ++i) sa();
        cout << round(ans) << "
    ";
    }
    

    技巧

    1.由于较为玄学,所以需要多跑几次模拟退火

    2.更改随机种子

    3.卡时间,例如小于0.8秒就一直跑模拟退火,充分利用测评时间

    4.超时说明降温系数太大了,降温过程太慢,方法:可以把0.999改为0.99

  • 相关阅读:
    模式对象管理
    Oracle数据库实例
    github使用简介
    Oracle数据库安装与连接与简介
    利益相关者分析
    问题账户需求分析
    2018春季学期需求工程概论阅读计划
    JAXB在Java 9/10并且使用Tomcat 9的问题
    mysql 备份 恢复
    IntelliJ IDEA安装bower
  • 原文地址:https://www.cnblogs.com/dyhaohaoxuexi/p/14403453.html
Copyright © 2020-2023  润新知