模拟退火算法:从物理原理到Python实现与数学建模实战
1. 项目缘起:为什么数学建模离不开模拟退火?
如果你参加过数学建模竞赛,或者处理过任何带“优化”二字的实际问题,大概率会和我有同样的感受:题目读懂了,模型也建出来了,但最后卡在了“怎么解”这一步。尤其是当你的目标函数长得奇形怪状,或者约束条件多到让人头皮发麻时,传统的精确算法(比如线性规划里的单纯形法)要么根本用不了,要么算到天荒地老。这时候,你就需要一种“不那么讲道理”,但“特别管用”的武器——启发式算法。而模拟退火,绝对是这类武器库里的明星选手。
我第一次在国赛里用上模拟退火,是为了解决一个复杂的设施选址问题。目标是要在几十个候选点里选出几个,使得总运输成本最低,同时还要满足覆盖范围、容量上限等一堆限制。这问题本质上是个组合爆炸的0-1规划,用常规方法几乎无解。在焦头烂额之际,我翻到了一篇往届优秀论文,里面用模拟退火算法漂亮地拿到了近乎最优的解。从那以后,无论是路径规划、参数拟合,还是图像处理中的优化问题,模拟退火都成了我工具箱里的常客。
简单来说, 模拟退火算法是一种受物理中固体退火过程启发的随机优化算法 。它的核心思想非常巧妙:模仿金属加热后缓慢冷却(退火)的过程,在搜索过程中以一定的概率接受比当前解更差的“坏解”。这个“接受坏解”的概率,会随着一个叫做“温度”的参数逐渐降低而减小。一开始温度高,算法可以大胆地“四处乱逛”,跳出局部最优的陷阱;随着温度降低,它变得越来越“保守”,最终稳定在一个(希望是全局的)最优解附近。
为什么它在数学建模中如此受欢迎?我总结下来有三大原因:
- 通用性强 :不要求目标函数连续、可导,对问题的数学性质几乎没限制,只要你能定义出一个“解”和衡量解好坏的“能量函数”(即目标函数),就能套用。
- 避免早熟 :因为能概率性接受差解,它比纯粹的“爬山法”更不容易陷入局部最优,这在解决多峰优化问题时是巨大优势。
- 实现简单 :算法框架清晰,核心代码往往一两百行Python就能搞定,非常适合在时间紧迫的竞赛中快速实现和调整。
接下来,我就结合自己多次实战的经验,手把手带你拆解模拟退火算法的Python实现,并分享几个在数学建模中真正好用的技巧和避坑指南。
2. 算法核心:从物理退火到代码实现的思维转换
理解模拟退火,关键在于建立物理过程与优化算法之间的映射关系。很多教程只扔给你公式,但没讲清楚为什么这么设计。这里我用自己的理解帮你捋顺这个逻辑链。
2.1 物理隐喻与算法参数的对应关系
想象一下铁匠打铁。他要打造一把锋利的刀,会把铁块烧红(高温),这时铁原子内能高,运动剧烈,结构处于一种高度随机的状态。然后,铁匠会非常缓慢地冷却它(退火),让原子有足够的时间重新排列,最终形成坚硬、稳定的晶体结构(能量最低状态)。如果冷却太快(淬火),原子来不及找到最佳位置,就会形成有内部应力的、不那么坚固的结构(局部最优)。
模拟退火算法完美复现了这个过程:
- 解的状态 (State) -> 金属的微观状态 。在优化问题中,这就是一个可能的答案,比如一组选址方案、一条旅行路线。
- 目标函数值 (Energy) -> 系统的内能 。我们的目标是最小化成本或最大化收益,对应着寻找系统能量最低的状态。
- 温度 (Temperature, T) -> 实际温度 。这是算法最核心的控制参数。高温对应搜索的“大胆探索”阶段,低温对应“精细收敛”阶段。
- 状态转移 (邻域搜索) -> 原子的随机扰动 。如何从当前解产生一个新解?这需要你设计一个“邻域函数”,比如随机交换两个城市的位置、随机改变一个选址点的状态。
- Metropolis接受准则 -> 热力学概率 。这是算法的灵魂。新解是否被接受,不仅看它是否更好(能量更低),即使它更差,也有一定概率被接受。这个概率由公式决定:
P = exp(-ΔE / T),其中ΔE是新解与旧解的能量差(对于最小化问题,ΔE = 新能量 - 旧能量)。- 温度T很高时 :即使
ΔE很大(解变差很多),exp(-ΔE / T)也可能接近1,算法几乎“来者不拒”,广泛探索解空间。 - 温度T很低时 :
exp(-ΔE / T)会变得很小,算法几乎只接受更好的解,行为类似局部搜索,收敛到当前区域的最优解。
- 温度T很高时 :即使
2.2 算法流程的代码骨架
理解了隐喻,我们来看一个最经典的模拟退火流程,它通常包含三个循环:
- 外循环 :温度下降过程。控制整个算法的“冷却进度”。
- 内循环 (马尔可夫链长度) :在每个温度下,进行足够多次的状态尝试,让系统达到该温度下的“热平衡”。
- 核心迭代 :每次尝试中,产生新解、计算能量差、根据Metropolis准则决定是否接受。
下面是一个高度抽象、但逻辑完整的Python伪代码框架:
def simulated_annealing(initial_solution, initial_temp, final_temp, alpha, max_iter):
"""
模拟退火算法主函数
Args:
initial_solution: 初始解
initial_temp: 初始温度
final_temp: 终止温度
alpha: 温度衰减系数 (0 < alpha < 1)
max_iter: 每个温度下的迭代次数(马尔可夫链长度)
Returns:
best_solution: 找到的历史最优解
best_energy: 对应的历史最优能量值
history: 记录过程用于绘图分析
"""
current_solution = initial_solution.copy()
current_energy = calculate_energy(current_solution)
best_solution = current_solution.copy()
best_energy = current_energy
T = initial_temp
history = {'temp': [], 'energy': [], 'best_energy': []}
while T > final_temp:
for i in range(max_iter):
# 1. 在當前解的鄰域內產生一個新解
new_solution = get_neighbor(current_solution)
new_energy = calculate_energy(new_solution)
# 2. 計算能量差 (我們假設是最小化問題)
delta_e = new_energy - current_energy
# 3. Metropolis準則: 決定是否接受新解
if delta_e < 0:
# 新解更好,直接接受
accept = True
else:
# 新解更差,以一定概率接受
probability = math.exp(-delta_e / T)
if random.random() < probability:
accept = True
else:
accept = False
# 4. 更新當前狀態
if accept:
current_solution = new_solution
current_energy = new_energy
# 5. 更新歷史最優解
if current_energy < best_energy:
best_solution = current_solution.copy()
best_energy = current_energy
# 記錄當前溫度下的狀態,用於後續分析
history['temp'].append(T)
history['energy'].append(current_energy)
history['best_energy'].append(best_energy)
# 6. 降溫 (幾何降溫最常用)
T = T * alpha
return best_solution, best_energy, history
这个框架是通用的,但其中三个函数需要你根据具体问题来“填空”: calculate_energy (目标函数)、 get_neighbor (邻域生成函数)、以及初始解的构造。这也是模拟退火“易学难精”的地方,算法的效果很大程度上取决于你对这三个部分的精心设计。
3. 实战拆解:以旅行商问题(TSP)为例的完整实现
光讲理论太抽象,我们用一个数学建模中的经典问题——旅行商问题来实战。假设有N个城市,给出它们两两之间的距离,要求找出一条访问每个城市恰好一次并回到起点的最短路径。TSP是NP-Hard问题,非常适合用模拟退火求解。
3.1 问题定义与能量函数设计
首先,我们需要把问题“映射”到算法框架里。
- 解 (Solution) :一个城市的访问顺序序列,例如
[0, 3, 1, 2, 4]表示从城市0出发,依次访问城市3、1、2、4,最后回到城市0。 - 能量函数 (Energy) :路径的总长度。我们的目标是最小化它。
- 邻域操作 (Neighbor) :如何从当前路径产生一条“稍作改动”的新路径?常见操作有:
- 交换 (Swap) :随机选择两个位置,交换这两个位置上的城市。
- 逆序 (Reverse) :随机选择一段子路径,将其顺序完全颠倒。
- 插入 (Insert) :随机选择一个城市,将其插入到另一个随机位置。
不同的邻域操作会影响算法的搜索效率和最终效果。通常, 逆序 操作在TSP中效果很好,因为它能较大程度地改变路径结构,有助于跳出局部最优。
3.2 Python代码逐行精讲
下面是一个求解TSP的完整模拟退火Python实现,我加入了大量注释和心得。
import math
import random
import numpy as np
import matplotlib.pyplot as plt
def calculate_total_distance(route, distance_matrix):
"""计算一条路径的总距离(能量函数)"""
total = 0.0
num_cities = len(route)
for i in range(num_cities):
# 从城市route[i]到城市route[(i+1)%num_cities]的距离
total += distance_matrix[route[i]][route[(i + 1) % num_cities]]
return total
def get_neighbor_by_reverse(route):
"""通过逆序一段子路径来产生邻域解"""
new_route = route.copy() # 重要!必须复制,避免修改原解
n = len(new_route)
# 随机选择两个不同的索引,确保 i < j
i, j = sorted(random.sample(range(n), 2))
# 将 i 到 j 之间的路径逆序
new_route[i:j+1] = reversed(new_route[i:j+1])
return new_route
def simulated_annealing_tsp(distance_matrix, initial_temp=1000, final_temp=1e-3, alpha=0.99, max_iter_per_temp=100):
"""
针对TSP的模拟退火算法
Args:
distance_matrix: 距离矩阵,N x N,dist[i][j]表示城市i到j的距离。
"""
num_cities = len(distance_matrix)
# 1. 生成初始解:一个随机的城市排列
current_route = list(range(num_cities))
random.shuffle(current_route)
current_distance = calculate_total_distance(current_route, distance_matrix)
best_route = current_route.copy()
best_distance = current_distance
T = initial_temp
history = {'temp': [], 'current_dist': [], 'best_dist': []}
iteration = 0
while T > final_temp:
for _ in range(max_iter_per_temp):
# 产生新解
new_route = get_neighbor_by_reverse(current_route)
new_distance = calculate_total_distance(new_route, distance_matrix)
delta = new_distance - current_distance
# Metropolis准则
if delta < 0 or random.random() < math.exp(-delta / T):
current_route = new_route
current_distance = new_distance
# 更新历史最优
if current_distance < best_distance:
best_route = current_route.copy()
best_distance = current_distance
iteration += 1
# 记录数据
history['temp'].append(T)
history['current_dist'].append(current_distance)
history['best_dist'].append(best_distance)
# 降温
T *= alpha
# 可选:打印进度,在调试时非常有用
if len(history['temp']) % 50 == 0:
print(f"Temp: {T:.4f}, Best Dist: {best_distance:.2f}, Current Dist: {current_distance:.2f}")
return best_route, best_distance, history
# ========== 测试与可视化 ==========
if __name__ == "__main__":
# 随机生成20个城市的坐标和距离矩阵(欧氏距离)
num_cities = 20
np.random.seed(42) # 固定随机种子,确保结果可复现
coordinates = np.random.rand(num_cities, 2) * 100
# 计算欧氏距离矩阵
dist_matrix = np.zeros((num_cities, num_cities))
for i in range(num_cities):
for j in range(num_cities):
dist_matrix[i][j] = np.linalg.norm(coordinates[i] - coordinates[j])
# 运行模拟退火算法
best_route, best_dist, history = simulated_annealing_tsp(
dist_matrix,
initial_temp=1000,
final_temp=1e-5, # 终止温度可以设得更低,以获得更稳定的解
alpha=0.995, # 降温更慢,搜索更充分
max_iter_per_temp=200
)
print(f"最优路径长度: {best_dist}")
print(f"最优访问顺序: {best_route}")
# 绘制优化过程收敛曲线
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(history['best_dist'], label='Best Distance', linewidth=2)
plt.plot(history['current_dist'], label='Current Distance', alpha=0.6)
plt.xlabel('Iteration (per temperature step)')
plt.ylabel('Distance')
plt.title('SA Convergence Process')
plt.legend()
plt.grid(True, linestyle='--', alpha=0.5)
# 绘制最优路径图
plt.subplot(1, 2, 2)
# 按最优顺序重新排列坐标
best_coords = coordinates[best_route]
# 闭合路径
best_coords = np.vstack([best_coords, best_coords[0]])
plt.plot(best_coords[:, 0], best_coords[:, 1], 'o-', linewidth=2, markersize=8)
plt.scatter(coordinates[:, 0], coordinates[:, 1], c='red', s=50, zorder=5)
for i, (x, y) in enumerate(coordinates):
plt.text(x, y, str(i), fontsize=9, ha='center', va='center')
plt.xlabel('X Coordinate')
plt.ylabel('Y Coordinate')
plt.title(f'Optimal TSP Route (Distance: {best_dist:.2f})')
plt.axis('equal')
plt.grid(True, linestyle='--', alpha=0.3)
plt.tight_layout()
plt.show()
代码要点与心得:
- 距离矩阵 :对于TSP,预先计算好所有城市两两之间的距离矩阵是最高效的做法,避免在能量函数中重复计算距离。
- 邻域操作的选择 :我选择了
逆序操作。实测中发现,对于TSP这类问题,逆序操作比单纯交换两个城市能产生“破坏性”更强、也更有可能改进路径的新解,搜索效率更高。 - 复制的重要性 :在
get_neighbor_by_reverse函数中,new_route = route.copy()这行代码至关重要。如果不进行深拷贝,直接修改列表,会导致当前解被意外改变,破坏算法的状态转移逻辑,这是新手极易犯的错误。 - 随机种子 :在测试时设置
np.random.seed()和random.seed()可以确保每次运行结果一致,便于调试和比较不同参数的效果。但在正式求解时应该去掉,以体现算法的随机性。
运行这段代码,你会看到算法如何从一条混乱的随机路径,逐步优化成一条相对合理的短路径,同时收敛曲线图能清晰展示“能量”下降和“跳出”局部最优的过程。
4. 参数调优:如何让模拟退火在你的问题上“火力全开”
模拟退火有多个关键参数,调参是影响算法性能的核心环节。很多人把模拟退火效果不好归咎于算法本身,其实往往是参数没调对。下面这张表总结了核心参数、常见设置和调优逻辑:
| 参数 | 物理意义 | 常见设置/影响 | 调优策略与心得 |
|---|---|---|---|
| 初始温度 (T0) | 搜索初期的“活跃度” | 通常设置较大值,使初始接受差解的概率 ~1。可用公式估算: T0 = -ΔE_avg / ln(P0) ,其中P0是初始接受概率(如0.8),ΔE_avg是随机解能量差的平均值。 |
太高 :浪费计算时间在早期无意义的搜索上。 太低 :过早陷入局部搜索,失去全局探索能力。 我的经验 :对于数值型问题,可以设为目标函数值范围的若干倍(如100-1000倍)。先跑几次粗略估计目标函数值的波动范围。 |
| 终止温度 (Tf) | 停止搜索的阈值 | 一个很小的正数,如1e-3, 1e-5, 1e-8。 | 当温度降到Tf时,算法几乎只接受好解,搜索趋于停止。 我的经验 :通常和降温系数α配合使用。如果追求高精度,可以设得更低(如1e-8),但计算时间会增加。可以观察能量曲线,当连续多次迭代最优解不再变化时,即可提前终止。 |
| 降温系数 (α) | 温度下降的速度 | (0, 1)之间的数,常用0.8~0.999。越接近1,降温越慢。 | 核心参数 !对结果影响巨大。 α较大(如0.99) :降温慢,在每个温度下搜索更充分,更可能找到全局最优,但耗时极长。 α较小(如0.8) :降温快,收敛快,但容易陷入局部最优。 我的经验 :在数学建模竞赛中,时间有限,我常用0.95~0.99。可以先快速用大α(如0.8)跑一遍看大致趋势,再用小α(如0.995)精细搜索。 |
| 马尔可夫链长度 (L) | 每个温度下的迭代次数 | 与问题规模相关,通常为问题维度的若干倍(如100*n)。 | 确保系统在每一个温度下都能达到“热平衡”。 太长 :计算开销大。 太短 :温度下降太快,搜索不充分。 我的经验 :一个实用的方法是 自适应长度 。当连续若干次(如10次)迭代都被拒绝时,可以认为在该温度下已趋于平衡,提前结束内循环,跳到降温步骤。这能大幅提升效率。 |
| 邻域函数 | 定义如何产生新解 | 问题相关,是算法设计的核心。 | 设计原则 :新解应与当前解“相似但不同”,变化不宜过大或过小。 我的经验 :对于组合优化(如TSP),交换、逆序、插入是经典操作。对于连续函数优化,新解可以在当前解基础上加上一个随机扰动,如 x_new = x_current + random.uniform(-step, step) ,并且这个 step 可以随着温度降低而减小。 |
一个实用的调参流程:
- 固定其他,调α和L :先设置一个较高的T0和较低的Tf,然后主要调整α和L。观察收敛曲线,理想的曲线应该是:初期能量剧烈波动并缓慢下降(高温探索期),中期波动减小但仍有“跳跃”(中温过渡期),后期平滑收敛到一条稳定线(低温收敛期)。如果曲线一开始就平滑下降,说明T0可能太低或α太小;如果直到最后还在剧烈波动,说明Tf太高或α太大。
- 使用更智能的降温策略 :除了几何降温(
T = T * α),还可以尝试:- 线性降温 :
T = T - delta,但后期降温可能太慢。 - 自适应降温 :根据当前解的接受率来动态调整降温速度。例如,如果当前温度下的接受率很高,说明还没充分搜索,可以慢点降温;反之则快点降温。
- 线性降温 :
- 记录与可视化 :像上面的示例代码一样,记录每个温度下的当前解和最优解。绘制收敛图是调试参数最直观的方式,没有之一。
5. 数学建模实战技巧:从“能用”到“好用”的跨越
在数学建模竞赛中,仅仅实现一个能跑的模拟退火算法是不够的。你需要让它高效、稳健,并且能无缝嵌入到你的整体建模方案中。以下是我从多次竞赛中总结出的高阶技巧。
5.1 与其他算法/策略的混合使用
模拟退火很少单独使用,聪明的做法是与其他方法结合,取长补短。
- 与局部搜索结合(两阶段法) :先用模拟退火进行全局“粗搜”,找到一个不错的区域。然后以这个解作为起点,使用更高效的局部搜索算法(如梯度下降、变邻域搜索)进行“精搜”。这相当于用模拟退火跳出局部最优,再用局部搜索快速收敛到精确解。
- 与构造性启发式结合 :对于TSP、调度等问题,先用一个简单的贪婪算法(如最近邻法)生成一个较好的初始解,而不是完全随机初始解。这能为模拟退火提供一个高起点的“跳板”,大幅减少前期盲目搜索的时间。
- 并行化与多起点 :模拟退火的内循环迭代是相互独立的,非常适合并行计算。你可以同时跑多个独立链(从不同初始解开始),最后取最优结果。这在拥有多核CPU的计算机上能极大提速。Python中可以用
multiprocessing库实现。
5.2 处理复杂约束的实用方法
数学建模问题往往带有复杂的约束条件(如容量限制、时间窗口、互斥关系)。模拟退火本身不处理约束,我们需要将约束“融合”到算法中。常用方法有:
- 罚函数法(最常用) :将约束违反的程度作为一个惩罚项加到目标函数(能量函数)中。
新的能量 = 原始目标函数值 + 惩罚系数 * 约束违反量惩罚系数需要仔细调整。一开始可以设小一点,让算法有空间探索;在后期(低温阶段)可以增大惩罚系数,迫使解向可行域靠近。 - 修复法 :在邻域操作产生新解后,如果新解不可行,则通过一个“修复”程序将其调整为可行解。例如,在背包问题中,如果新解的总重量超限,就随机移除一些物品直到满足约束。这种方法能保证搜索始终在可行域内,但修复逻辑的设计需要技巧。
- 解码器法 :让算法在一个简单的、无约束的编码空间搜索(如一个0-1序列),然后通过一个确定的“解码”规则,将这个编码映射为满足所有约束的实际解。这需要巧妙的编码设计。
注意 :罚函数法虽然简单,但惩罚系数的选择是个艺术。系数太小,算法会一直在不可行域“闲逛”;系数太大,会过早地将搜索限制在可行域边界,可能错过全局最优。一个策略是使用 动态惩罚系数 ,让其随着迭代次数或温度下降而增加。
5.3 结果稳定性分析与论文写作要点
在论文中,你不能只说“我用模拟退火求出了一个解”。你需要证明这个解是可靠的、高质量的。
- 多次运行与统计 :由于模拟退火的随机性,单次运行的结果具有偶然性。你应该独立运行算法多次(如30次),记录每次得到的最优解和运行时间,计算平均值、标准差、最优值、最差值。这能有力说明算法的稳定性和鲁棒性。
- 收敛性分析 :像我们示例代码中那样,绘制 能量(目标函数值)随迭代次数变化的曲线 。在论文中放上这张图,并指出:“如图所示,算法在初期进行广泛的全局探索,能量波动较大;随着温度降低,算法逐渐收敛,最终稳定在一个较优的解附近。” 这比干巴巴的文字有说服力得多。
- 对比实验 :如果可能,将你的模拟退火结果与一些基准算法对比,如贪婪算法、遗传算法、或者商业求解器(如Gurobi, CPLEX)在小型算例上的精确解。用表格展示对比数据,突出模拟退火在求解质量或时间上的优势。
- 参数设置的说明 :在论文的“算法设计”部分,清晰地列出你使用的所有参数(T0, Tf, α, L等),并简要说明选择这些值的依据(例如,“通过初步实验,我们发现当α=0.95时,算法能在求解质量和时间效率之间取得较好平衡”)。这体现了你工作的严谨性。
6. 常见“坑点”与排查指南
即使理解了原理,自己实现时还是会遇到各种问题。这里列出几个我踩过的坑和解决办法。
6.1 算法“早熟”或陷入局部最优
- 现象 :算法很快就收敛到一个解,并且不再变化,但这个解的质量明显不高。
- 可能原因与排查 :
- 初始温度T0太低 :算法一开始就没能充分探索。 解决 :提高T0,确保初始接受差解的概率足够高(例如>0.8)。
- 降温速度太快(α太小) :系统还没来得及在各个温度下达到平衡,就迅速冷却了。 解决 :增大α(如从0.9调到0.99),或者增加马尔可夫链长度L。
- 邻域结构设计不合理 :新解与当前解差异太小,搜索步长受限。 解决 :设计变化幅度更大的邻域操作。对于连续问题,可以尝试让随机扰动的步长与温度相关(
step_size * T),温度高时步长大,温度低时步长小。 - 陷入“高原” :目标函数在某个区域非常平坦,算法在大量同等质量的解之间徘徊,无法找到下降方向。 解决 :可以考虑在能量函数中增加一个极小的随机扰动,或者引入“重启动”机制——当最优解长时间未更新时,从历史最优解出发,适当提高温度重新搜索。
6.2 算法运行时间过长
- 现象 :程序跑了很久都没结束,或者收敛速度极慢。
- 可能原因与排查 :
- 目标函数/邻域函数计算太慢 :这是性能瓶颈最常见的原因。 解决 :使用向量化计算(NumPy)、缓存中间结果、检查是否有重复计算。对于TSP,使用预计算的距离矩阵而不是每次实时计算距离。
- 马尔可夫链长度L设置过大 :在每个温度下做了太多无用功。 解决 :实现 自适应链长 ,当接受率低于某个阈值(如5%)时,提前结束当前温度下的迭代。
- 终止温度Tf设置过低 :为了追求不必要的精度,让算法在极低温度下运行了过多轮。 解决 :设置一个合理的Tf,或者添加一个基于迭代次数或最优解稳定性的终止条件(如“连续100次温度下降,最优解未改善”)。
- 降温系数α太接近1 :如α=0.999,需要极多的外循环才能降到终止温度。 解决 :在精度允许范围内,适当降低α。
6.3 结果波动大,不稳定
- 现象 :每次运行得到的最优解差异很大。
- 可能原因与排查 :
- 随机性本身 :这是启发式算法的固有特点。 解决 :这不是bug,而是特性。应对方法是 多次运行取最优 ,并在论文中报告统计结果(均值、标准差等),这反而是算法鲁棒性分析的一部分。
- 参数过于敏感 :特别是初始温度和降温系数。 解决 :进行参数敏感性分析。固定其他参数,微调某一个,观察结果的变化。选择在较宽范围内都能给出稳定较好结果的参数组合。
- 终止条件不充分 :算法可能在尚未完全收敛时就停止了。 解决 :除了温度,增加基于最优解稳定性的终止判断,例如“最优解连续N个温度周期未发生变化”。
最后,分享一个调试小技巧: 打印日志 。在关键位置(如每次降温时、更新历史最优时)打印出当前温度、当前能量、历史最优能量、接受率等信息。这些日志能帮你直观地了解算法的运行状态,是定位问题最快的方式。在代码开发阶段可以详细打印,最终提交版本可以关闭或简化日志。
更多推荐


所有评论(0)