⭐⭐⭐模拟退火(SA)⭐⭐⭐

一、什么是模拟退火(Simulated Annealing)

        模拟退火算法(SA)是一种基于概率的通用优化算法,用来在一个大的搜寻空间内寻找问题的最优解。
        模拟退火算法从某一较高初温出发,伴随温度参数的不断下降,结合概率突跳特性在解空间中随机寻找目标函数的全局最优解,即即在局部最优解能概率性地跳出并最终趋于全局最优

二、模拟退火的基本概念

   1  温度(T)

        在物理中我们知道,温度越高,物体内部分子热运动越剧烈;温度越低,分子热运动越平静。

        
        温度在模拟退火算法中的作用体现可以类比物理中分子的热运动:温度越高,分子活动越剧烈,对当前状态产生的偏移越大。模拟退火算法会根据当前温度随机对当前状态进行偏移得到新状态。
         令X,为当前状态,Xh+1为随机偏移得到的新状态:

        

        在模拟退火算法中,温度会从较高的起始温度逐渐降低到结束温度。起始温度和结束温度作为模拟退火的两个参数,需要根据问题题的实际情况选取。 

   2   温度衰减率(K)

        温度衰减率即在降温过程中,温度降低的速度,即后一时刻的温度与前一时刻温度的比值。        


        在模拟退火算法中,温度衰减率作为参数之一,可以根据问题题的具体情况和需求进行设置。

   3、Metropolis准则⭐⭐⭐

        Metropolis准则是确定是否选择当前解的规则。模拟退火算法会随机对当前状态进行偏移产生新状态,如果新状态对应的解比当前前状态对应的解更优,就采用该新状态;如果新解劣于当前解,那么就以一定概率采用新状态或保持不变。这种选择解的规则就称之为Metropolis准则。

总的来说,对于新解En+1和当前解En,采用新解的概率:
求最小值:
        

求最大值:

 4、Markov链(L)

        Markov链是概率论和数理统计中的概念。Markov链在模拟退火算法中的作用是:Markov链的长度决定了在每个温度下,对当前状态进行偏移的次数。
        令L为Markov链的长度,L为模拟退火算法的参数之一,需要根据问题的实际情况选取。

⭐⭐⭐5、为什么要进行随机偏移、为什么Metropolis准则要以一定概率选则劣解?

        避免陷入局部最优:在搜索初期,温度较高时,算法需要有较大的自由度来探索解空间。如果只接受优解(比当前解更好的解),那么算法很容易陷入局部最优解,因为一旦进入局部最优区域,就很难再跳出来。通过以一定概率接受劣解,算法可以跳出局部最优解的陷阱,继续在解空间中搜索,从而有可能找到全局最优解。

三、模拟退火的步骤

        模拟退火遵循以下步骤


        ①  从初始温度开始
        ②对于当前温度T,对状态进行L次随机偏移
        ③对于每次偏移,对偏移后的新状态进行求解,并根据Metropolis准则选择是否采用该新状态。
        ④温度衰减
        ⑤如果当前温度低于结束温度,算法结束

四、例

点点之遥

题目描述
在二维平面上有几个点,其中第i个点的坐标为(xi,yi)。现请你在空间中找出任意一个点,使得该点到这几个点的距离之和最小。问这最小的距离之和为多少?


输入描述
第一行输入一个正整数n。
接下来几行每行包含两个整数 xi,yi,表示第i个点的坐标。
1 ≤ n ≤ 10^3, 0 ≤ xi,yi<=10^5


输出描述
输出仅一行,包含一个数,表示答案(四舍五入取整)。
 

#include <bits/stdc++.h>
#include <ctime>

using namespace std;
// 退火系数,控制温度下降的速度,每次温度乘以该系数降低
const double K = 0.99;
// 初始温度,模拟退火算法开始时的温度
const double ST = 1e6;
// 终止温度,当温度降到该值以下时,算法停止迭代
const double ET = 1e-9;
// 每个温度下的迭代次数,在每个温度下进行多次尝试以寻找更优解
const double L = 100;

// 用于存储输入的 n 个点的 x 坐标
int x[1004];
// 用于存储输入的 n 个点的 y 坐标
int y[1004];
// 表示输入的点的数量
int n;

// 目标函数,计算点 (nx, ny) 到所有 n 个点的欧几里得距离之和
double f(double nx, double ny) {
    double dis = 0;
    // 遍历所有的 n 个点
    for (int i = 1; i <= n; i++) {
        // 计算当前点 (nx, ny) 到第 i 个点 (x[i], y[i]) 的欧几里得距离
        // pow(a, 2) 计算 a 的平方,sqrt 计算平方根
        dis += sqrt(pow(nx - x[i], 2) + pow(ny - y[i], 2));
    }
    return dis;
}

// 模拟退火算法的实现函数
double sa() {
    // 初始化温度为初始温度 ST
    double T = ST;
    // 初始化当前点的 x 坐标为 0
    double X = 0;
    // 初始化当前点的 y 坐标为 0
    double Y = 0;
    // 计算初始点 (X, Y) 的目标函数值,即能量 E
    double E = f(X, Y);
    // 初始化最优解为初始能量 E
    double ans = E;

    // 当温度 T 大于终止温度 ET 时,继续迭代
    while (T > ET) {
        // 在每个温度下进行 L 次迭代
        for (int i = 1; i <= L; i++) {
            // 生成新点的 x 坐标,在当前点 X 的基础上,根据当前温度 T 和随机数进行偏移
            // rand() 生成一个 0 到 RAND_MAX 之间的随机整数
            // (rand() * 2 - RAND_MAX) 得到一个 -RAND_MAX 到 RAND_MAX 之间的随机数
            double nX = X + (rand() * 2 - RAND_MAX) * T;
            // 生成新点的 y 坐标,同理
            double nY = Y + (rand() * 2 - RAND_MAX) * T;
            // 计算新点 (nX, nY) 的目标函数值,即新能量 nE
            double nE = f(nX, nY);
            // 计算新能量与当前能量的差值
            double dE = nE - E;

            // 判断是否接受新点
            // 如果新能量小于当前能量(dE < 0),则肯定接受新点
            // 或者以一定概率接受能量增加的新点,概率由 exp(-dE / T) 决定
            // exp 是指数函数,rand() / RAND_MAX 得到一个 0 到 1 之间的随机小数
            if (dE < 0 || exp(-dE / T) > rand() / RAND_MAX) {
                // 更新当前点的 x 坐标为新点的 x 坐标
                X = nX;
                // 更新当前点的 y 坐标为新点的 y 坐标
                Y = nY;
                // 更新当前能量为新能量
                E = nE;
                // 更新最优解,取当前最优解和新能量中的较小值
                ans = min(ans, E);
            }
        }
        // 降低温度,乘以退火系数 K
        T = K * T;
    }
    return ans;
}

int main()
{
    // 根据当前时间设置随机数种子,确保每次运行程序时生成的随机数序列不同
    srand(time(NULL));
    // 读取输入的点的数量 n
    cin >> n;
    // 循环读取 n 个点的坐标
    for (int i = 1; i <= n; i++) {
        // 读取第 i 个点的 x 坐标
        cin >> x[i];
        // 读取第 i 个点的 y 坐标
        cin >> y[i];
    }

    // 调用模拟退火算法函数 sa 求解最小距离和,并输出结果
    cout << sa();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值