ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

模拟退火算法:从物理退火到组合优化的全局寻优利器

模拟退火算法:从物理退火到组合优化的全局寻优利器 1. 项目概述从“退火”到“寻优”的智慧迁移如果你在数学建模、优化算法或者机器学习领域摸爬滚打过一阵子大概率会对“模拟退火算法”这个名字既熟悉又头疼。熟悉是因为它在解决组合优化、函数寻优这类“NP难”问题上名声在外头疼则是因为其原理听起来有点玄乎——好好的一个优化算法怎么就跟金属冶炼里的“退火”扯上关系了我第一次接触它时也是一头雾水直到后来亲手用它解决了一个实际的车间调度问题才真正体会到这种“物理过程数学化”的巧妙之处。简单来说模拟退火算法是一种受固体退火过程启发而得到的通用概率性优化算法。它的核心思想非常直观模仿金属从高温熔融状态缓慢冷却退火最终结晶成能量最低的稳定状态这一物理过程来寻找一个复杂问题的全局最优解或近似最优解。在数学建模竞赛中无论是让你规划最短送货路线旅行商问题还是安排工厂生产顺序作业车间调度亦或是寻找复杂函数的最低点当你发现常规的贪心算法容易“卡”在局部最优解里出不来时模拟退火往往能成为你工具箱里那枚打破僵局的“钥匙”。它不保证每次都能找到绝对的最优解但在有限的时间和计算资源内它能以很高的概率找到一个非常优秀的近似解。这种在“绝对精确”和“实际可行”之间的平衡正是数学建模解决现实问题的精髓所在。接下来我会结合自己多次使用的经验拆解这个算法的每一个核心环节并附上可直接运行的Python代码和避坑指南让你不仅能看懂更能直接用起来。2. 算法核心思想与物理隐喻深度解析理解模拟退火关键在于吃透它的物理隐喻。我们先把“算法”放一边想象一个铁匠打铁的场景。2.1 物理退火过程能量、温度与状态跃迁一块烧红的铁内部的原子处于剧烈的高能无序状态。如果铁匠把它直接丢进冷水里淬火原子来不及重新排列就会“冻结”在一种高能量的亚稳态导致铁器硬而脆。而退火的做法是让高温的铁块在空气中非常缓慢地冷却。在这个过程中原子有充足的时间进行微小的位置调整。在每一个温度下系统都会趋向于该温度对应的“热平衡”状态。随着温度逐渐降低系统的内能在这里可以理解为所有原子势能的总和也逐步降低。当温度降至室温时原子最终排列成规则的晶格结构达到能量最低的稳定状态。将这个物理过程映射到优化问题中就构成了模拟退火算法的骨架物理系统状态-优化问题的某个解。比如旅行商问题中的一条访问城市的顺序。系统能量 E-目标函数值 f(x)。我们希望找到使 f(x) 最小或最大的解 x。能量越低解的质量越好。温度 T-一个控制算法行为的核心参数。高温时算法接受“坏解”的概率大搜索范围广低温时算法趋于保守主要接受“好解”进行局部精细搜索。冷却进度表-温度 T 随时间迭代次数下降的策略。这是算法成败的关键决定了搜索的广度和深度。2.2 算法逻辑Metropolis准则与“偶尔的倒退”模拟退火最反直觉、也最精髓的部分在于它如何模拟原子在某一温度下的热平衡过程。这依赖于一个称为Metropolis接受准则的概率公式。假设当前解为S_old其目标函数值成本为C_old。我们通过某种方式例如随机交换两个城市顺序产生一个新解S_new其成本为C_new。如果C_new C_old新解更好我们总是接受这个新解。如果C_new C_old新解更差我们以一定的概率接受它。这个概率 P 由以下公式决定P exp(-(C_new - C_old) / T)这个公式是算法的灵魂。我们来拆解一下(C_new - C_old)代表解变差的“糟糕”程度。差值越大新解越差。T(温度)在分母上。当温度 T 很高时(C_new - C_old) / T的值会很小使得P exp(-一个小数)接近 1。这意味着在高温阶段算法几乎“来者不拒”即使是很差的解也有很大概率被接受。这相当于让系统有足够的能量“爬山”跳出当前的局部最优区域去探索解空间的其他部分。随着迭代进行温度 T 按照冷却进度表逐渐降低。此时(C_new - C_old) / T的值会变大导致概率 P 急剧下降。在低温阶段算法很难再接受差解行为越来越像传统的局部搜索在当前的优质解附近进行微调最终稳定下来。注意这个“以一定概率接受差解”的机制是模拟退火区别于爬山算法等贪婪算法的根本。爬山算法只接受更好的解因此一旦走到一个局部最优的“小山坡”顶就再也下不来了。而模拟退火通过“偶尔允许倒退”获得了跳出局部最优、寻找全局最优的潜力。3. 算法流程与关键参数全解构纸上谈兵终觉浅我们直接把算法的完整流程和每一个需要你手动设置的“旋钮”拆开来看。3.1 算法标准流程步骤一个标准的模拟退火算法流程可以概括为以下几步我通常会把它写成一个循环框架初始化随机生成一个初始解S设定一个足够高的初始温度T0确定每个温度下的迭代次数L称为马尔可夫链长度确定降温系数alpha(0 alpha 1)。外循环降温过程当温度T大于终止温度T_end时重复以下步骤 a.内循环热平衡过程在当前温度T下重复L次 i.产生新解通过预设的“邻域操作”在当前解S附近产生一个新解S‘。 ii.计算目标函数变化ΔC C(S’) - C(S)。 iii.Metropolis准则判断 - 若ΔC 0接受S‘作为新的当前解 (S S‘)。 - 若ΔC 0则以概率P exp(-ΔC / T)接受S‘。具体操作是生成一个 [0,1) 区间的随机数rand若rand P则接受S‘否则拒绝新解保持S不变。 b.降温按预定策略降低温度最常用的是T alpha * T。输出循环结束后将当前解S作为找到的最优或近似最优解输出。3.2 关键参数调优像调咖啡一样调算法算法的表现极大程度上依赖于几个关键参数的设置。没有放之四海而皆准的“最佳值”但有一些经验法则。参数含义与作用设置经验与技巧初始温度T0决定算法初期的搜索范围。太高则初期纯随机搜索效率低太低则过早陷入局部搜索。常用策略通过实验使算法初期的接受率接受新解的次数/总尝试次数在80%-95%之间。可以运行一个简短测试调整T0直至达到该范围。终止温度T_end算法停止的条件。温度低于此值时接受差解的概率极低继续迭代意义不大。通常设置为一个非常接近0的正数如1e-7。或者可以设置为当连续若干个温度下最优解都没有改进时停止。降温系数alpha控制温度下降的速度。越接近1降温越慢搜索越充分但耗时越长。典型值在[0.8, 0.99]之间。对于解空间复杂的问题建议使用0.95或更高进行慢速退火。马尔可夫链长度L每个温度下尝试产生新解的迭代次数。应保证在该温度下系统能达到“热平衡”。一个简单有效的方法是将其设为问题规模的常数倍。例如对于旅行商问题的N个城市可以设L 100 * N。也可以动态调整如直到接受或拒绝的解达到一定数量。邻域操作如何从当前解产生一个新解。这是与问题强相关的部分直接影响搜索效率。设计原则是新解应在当前解的“附近”变化不应过于剧烈。例如TSP问题常用“2-opt”随机反转一段路径或“交换两个城市位置”。实操心得参数调优是个“手感活”。我的建议是先固定一个经典的参数组合如 T0100, T_end1e-7, alpha0.98, L100*N跑一遍观察解的变化曲线和接受率。如果收敛太快就提高T0或alpha如果一直不收敛就降低alpha或增加L。记录下每次调整的结果你很快就能对当前问题的“脾气”有所把握。4. 实战用Python解决旅行商问题我们用一个经典的旅行商问题来贯穿整个实现过程。假设有10个城市它们的坐标随机生成目标是找到一条访问每个城市一次并回到起点的最短路径。4.1 问题定义与辅助函数首先我们定义问题的基础设施。import numpy as np import matplotlib.pyplot as plt import random import math # 设置随机种子确保结果可复现 np.random.seed(42) # 1. 生成模拟数据10个城市的坐标 (x, y) num_cities 10 cities np.random.rand(num_cities, 2) * 100 # 坐标在[0,100)区间 # 2. 计算距离矩阵提前算好避免在循环中重复计算这是重要的性能优化 def calculate_distance_matrix(points): n len(points) dist_matrix np.zeros((n, n)) for i in range(n): for j in range(n): if i ! j: dist_matrix[i][j] np.linalg.norm(points[i] - points[j]) # 欧氏距离 return dist_matrix dist_matrix calculate_distance_matrix(cities) # 3. 目标函数计算一条路径的总长度 def total_distance(path, dist_matrix): 计算给定路径的总距离。路径path是城市索引的列表如[0,3,1,2,...] total_dist 0 n len(path) for i in range(n): # 从城市path[i]到城市path[(i1)%n]的距离 total_dist dist_matrix[path[i]][path[(i1) % n]] return total_dist # 4. 可视化函数 def plot_route(cities, path, titleRoute): 绘制城市和路径 plt.figure(figsize(8,6)) plt.scatter(cities[:, 0], cities[:, 1], cred, s100, labelCities) route cities[path [path[0]], :] # 形成闭环 plt.plot(route[:, 0], route[:, 1], b-, linewidth1, labelPath) for i, (x, y) in enumerate(cities): plt.text(x, y, str(i), fontsize12, hacenter, vacenter) plt.xlabel(X Coordinate) plt.ylabel(Y Coordinate) plt.title(f{title} - Total Distance: {total_distance(path, dist_matrix):.2f}) plt.legend() plt.grid(True, alpha0.3) plt.show()4.2 邻域操作设计如何产生新解对于TSP产生新解邻域操作的方式直接决定了搜索的“步幅”。这里介绍两种最常用的def generate_new_solution_swap(current_path): 邻域操作1随机交换两个城市的位置。变化中等是常用操作。 new_path current_path.copy() # 随机选择两个不同的索引 i, j random.sample(range(len(new_path)), 2) new_path[i], new_path[j] new_path[j], new_path[i] return new_path def generate_new_solution_reverse(current_path): 邻域操作2随机反转一段子路径2-opt移动。局部优化能力强。 new_path current_path.copy() n len(new_path) # 随机选择两个切割点 i, j sorted(random.sample(range(n), 2)) # 反转i到j之间的片段 new_path[i:j1] reversed(new_path[i:j1]) return new_path # 我们可以随机选择一种操作或者交替使用 def generate_new_solution(current_path, operator_typerandom): if operator_type swap: return generate_new_solution_swap(current_path) elif operator_type reverse: return generate_new_solution_reverse(current_path) else: # random if random.random() 0.5: return generate_new_solution_swap(current_path) else: return generate_new_solution_reverse(current_path)4.3 模拟退火算法主程序实现现在将所有的部分组装起来。def simulated_annealing_tsp(cities, dist_matrix, T01000, T_end1e-7, alpha0.98, L2000, operatorrandom): 模拟退火算法求解TSP 参数 cities: 城市坐标数组 dist_matrix: 距离矩阵 T0: 初始温度 T_end: 终止温度 alpha: 降温系数 L: 每个温度的迭代次数马尔可夫链长度 operator: 邻域操作类型 (swap, reverse, random) 返回 best_path: 找到的最佳路径 best_distance: 最佳路径长度 history: 记录迭代过程中的最优距离用于绘图分析 num_cities len(cities) # 1. 初始化随机生成一条初始路径 current_path list(range(num_cities)) random.shuffle(current_path) current_distance total_distance(current_path, dist_matrix) # 记录全局最优解 best_path current_path.copy() best_distance current_distance T T0 history [best_distance] # 记录历史最优值 # 2. 外循环降温过程 iteration 0 while T T_end: for _ in range(L): # 3. 内循环每个温度下迭代L次 # 产生新解 new_path generate_new_solution(current_path, operator) new_distance total_distance(new_path, dist_matrix) delta new_distance - current_distance # Metropolis准则判断 if delta 0: # 新解更好直接接受 current_path, current_distance new_path, new_distance # 更新全局最优 if current_distance best_distance: best_path, best_distance current_path.copy(), current_distance else: # 新解更差以概率接受 p math.exp(-delta / T) if random.random() p: current_path, current_distance new_path, new_distance iteration 1 history.append(best_distance) # 每次迭代后都记录也可只在温度变化时记录 # 降温 T * alpha # 可选打印当前进度对于长时间运行的问题很有用 if iteration % (10 * L) 0: print(fIteration {iteration}, T{T:.4f}, Best Dist{best_distance:.2f}) print(fSA completed. Total iterations: {iteration}) print(fBest distance found: {best_distance:.2f}) return best_path, best_distance, history4.4 运行与结果分析让我们运行算法并看看效果。# 运行模拟退火算法 best_path, best_dist, history simulated_annealing_tsp( cities, dist_matrix, T01000, T_end1e-7, alpha0.995, # 使用较慢的降温以获得更好结果 L100 * num_cities, # 链长与问题规模相关 operatorrandom ) # 绘制最优路径 plot_route(cities, best_path, titleOptimal Route Found by SA) # 绘制优化过程曲线 plt.figure(figsize(10,5)) plt.plot(history, linewidth0.5) plt.xlabel(Iteration) plt.ylabel(Best Distance) plt.title(Simulated Annealing Optimization Process) plt.grid(True, alpha0.3) plt.show()运行这段代码你会看到两张图。第一张图展示了算法找到的最短路径城市之间的连线应该看起来相对规整没有明显的交叉对于随机点最优解通常近似一个不交叉的环。第二张图是优化过程曲线它非常有价值曲线初期会快速下降并伴有剧烈波动高温阶段广泛探索中期下降变缓波动减小中温阶段探索与开发并存后期逐渐趋于平稳低温阶段局部微调。如果曲线很早就变成一条水平线说明可能陷入了局部最优需要调高初始温度或降低降温速度。5. 参数调优实验与性能深度分析仅仅跑通一次是不够的。模拟退火的性能对参数敏感我们需要通过实验来理解每个参数的影响并找到适合当前问题的配置。5.1 单参数影响分析我们可以固定其他参数只改变一个来观察其影响。下面以降温系数alpha为例# 测试不同降温系数的影响 alphas [0.90, 0.95, 0.98, 0.995] results {} for a in alphas: print(f\nRunning SA with alpha{a}...) # 为了公平比较让总迭代次数大致相同。可以通过调整终止温度或链长来实现。 # 这里我们固定T0, T_end, 通过调整链长L来粗略控制总计算量。 # 更严谨的做法是控制总评估次数解的评价次数。 L_adj int(2000 * (0.98/a)) # 一个简单的调整使慢降温的链长稍短 best_path, best_dist, history simulated_annealing_tsp( cities, dist_matrix, T01000, T_end1e-7, alphaa, LL_adj, operatorreverse ) results[a] { best_dist: best_dist, history: history, final_iter: len(history) } print(f Best distance: {best_dist:.2f}) # 绘制对比曲线 plt.figure(figsize(12,6)) for a, res in results.items(): plt.plot(res[history], labelfalpha{a}, linewidth1) plt.xlabel(Iteration (Approximate)) plt.ylabel(Best Distance) plt.title(Impact of Cooling Coefficient (alpha) on SA Performance) plt.legend() plt.grid(True, alpha0.3) plt.ylim(bottommin([r[best_dist] for r in results.values()])*0.95) # 聚焦最优值附近 plt.show()你会观察到alpha0.90降温很快曲线迅速收敛但最终结果可能不是最好的。它搜索不够充分容易陷入局部最优。alpha0.995降温极慢曲线在很长时间内都在缓慢下降和波动最终通常能找到更好的解但耗时最长。alpha0.95和0.98在效果和效率之间取得了较好的平衡。注意事项这个实验的“总计算量”并不严格相等因为链长L我们做了简单调整。在实际科研或工程中更科学的对比方式是固定目标函数评估的总次数。例如规定算法最多计算50万次路径长度然后比较在这个预算下不同参数找到的解的质量。5.2 初始温度与接受率自适应策略手动设置初始温度T0是个麻烦事。一个实用的技巧是自适应确定初始温度。思路是从一个较低的T开始运行少量迭代计算解被接受的概率接受率。如果接受率太低比如0.8就将T加倍重复此过程直到接受率达到一个理想范围如0.8-0.95。def adaptive_initial_temperature(cities, dist_matrix, target_acceptance0.85, max_trials1000): 自适应估计一个合适的初始温度 num_cities len(cities) current_path list(range(num_cities)) random.shuffle(current_path) current_dist total_distance(current_path, dist_matrix) T 1.0 # 从一个较低的T开始 for _ in range(10): # 最多尝试10次加倍 accepted 0 total_moves 100 # 测试100次移动 for _ in range(total_moves): new_path generate_new_solution(current_path, random) new_dist total_distance(new_path, dist_matrix) delta new_dist - current_dist if delta 0 or random.random() math.exp(-delta / T): accepted 1 current_path, current_dist new_path, new_dist # 接受后更新当前解 acceptance_rate accepted / total_moves print(fT{T:.2f}, Acceptance Rate{acceptance_rate:.3f}) if target_acceptance * 0.9 acceptance_rate target_acceptance * 1.1: print(fFound suitable initial T: {T:.2f}) return T elif acceptance_rate target_acceptance: T * 2.0 # 接受率太低提高温度 else: T * 0.5 # 接受率太高降低温度虽然不常见 print(fUsing final T: {T:.2f}) return T # 使用自适应方法获取T0 estimated_T0 adaptive_initial_temperature(cities, dist_matrix) print(f\nEstimated initial temperature: {estimated_T0:.2f})这个方法能帮你省去反复手动尝试的麻烦尤其当你面对一个全新的、不了解其解空间规模的问题时。6. 进阶技巧混合策略与工程优化掌握了基础版本后我们可以通过一些进阶技巧来提升算法的性能和稳定性。6.1 记忆“历史最优解”在基础算法中我们用一个变量best_path和best_distance来跟踪全局最优。这是一个必须的做法。因为模拟退火的当前解current_path可能会因为接受差解而暂时变差如果没有这个记忆最终返回的可能只是一个局部较优解。我们的代码中已经实现了这一点。6.2 增加“回火”或“重启”机制这是应对复杂多峰函数的技巧。有时算法会陷入一个较深的局部最优即使有Metropolis准则也难以跳出。可以引入回火在降温过程中偶尔小幅地、短暂地提高温度给系统注入新的活力以跳出当前区域。重启当连续多次迭代最优解都没有改善时保留历史最优解然后从该解或一个随机解重新开始一轮退火过程但初始温度可以设得比第一次低一些。def simulated_annealing_with_restart(cities, dist_matrix, max_restarts3, **sa_kwargs): 带重启机制的模拟退火 global_best_path None global_best_dist float(inf) all_history [] for restart in range(max_restarts): print(f\n--- Restart {restart1}/{max_restarts} ---) # 后续重启时可以以之前找到的最优解为起点加入轻微扰动 if global_best_path is not None: initial_path global_best_path.copy() # 对最优解进行几次随机交换作为扰动作为新的起点 for _ in range(len(initial_path)//10): i, j random.sample(range(len(initial_path)), 2) initial_path[i], initial_path[j] initial_path[j], initial_path[i] # 注意我们的SA函数从随机解开始这里需要修改函数以接受初始解。 # 为简化我们这里仅演示思路实际需修改主函数接口。 pass best_path, best_dist, history simulated_annealing_tsp(cities, dist_matrix, **sa_kwargs) all_history.extend(history) # 合并历史记录 if best_dist global_best_dist: global_best_dist best_dist global_best_path best_path.copy() print(f - New global best found: {global_best_dist:.2f}) return global_best_path, global_best_dist, all_history6.3 并行化与计算加速模拟退火的内循环在每个温度下尝试L次新解是天然可以并行的因为每次尝试都是独立的。我们可以使用Python的multiprocessing库来加速。from multiprocessing import Pool, cpu_count def parallel_sa_worker(args): 每个工作进程运行的函数在一个温度下执行多次迭代 T, current_path, current_dist, dist_matrix, L_segment args best_local_dist current_dist best_local_path current_path.copy() for _ in range(L_segment): new_path generate_new_solution(current_path, random) new_dist total_distance(new_path, dist_matrix) delta new_dist - current_dist if delta 0 or random.random() math.exp(-delta / T): current_path, current_dist new_path, new_dist if current_dist best_local_dist: best_local_dist current_dist best_local_path current_path.copy() # 返回这个进程找到的最佳解和最终状态 return best_local_path, best_local_dist, current_path, current_dist # 注意完整的并行SA实现涉及进程间通信传递当前最优解和状态代码结构会更复杂。 # 上述 worker 函数提供了一个基本框架。主进程需要汇总各个worker的结果选择最好的一个作为下一轮的当前解。 # 并行化主要适用于L非常大的情况因为进程间通信也有开销。对于TSP这种目标函数计算total_distance是主要耗时的场景另一个更有效的优化是增量计算。当我们只是交换或反转路径中的一小段时不需要重新计算整条路径的长度只需要计算发生变化的那部分距离。这能带来数量级的性能提升。def total_distance_incremental(old_path, old_dist, i, j, dist_matrix, move_typeswap): 增量计算新路径的距离。 假设旧路径为old_path距离为old_dist。 我们进行了某种移动如交换i,j位置生成新路径new_path。 此函数计算new_path的距离避免全量计算。 n len(old_path) new_dist old_dist # 这里以交换操作为例实现增量更新逻辑 if move_type swap: # 交换 city_i 和 city_j # 受影响的边是...-i-i_next, ...-j-j_next, 以及 i_prev-i, j_prev-j # 需要减去旧边加上新边。具体实现需考虑i和j相邻等边界情况。 # 代码略实现较为繁琐但能极大提升速度。 pass return new_dist实操心得在数学建模竞赛中时间有限我通常优先采用以下策略确保算法有效1) 使用自适应初始温度2) 采用较慢的降温alpha0.9953) 链长L设为问题规模的100-200倍4)一定要实现并维护一个全局最优解的记忆变量。如果时间允许再考虑实现增量计算。并行化和重启机制通常用于对结果要求极高、计算资源充足的场合。7. 数学建模中的应用场景与赛题实战指南模拟退火在数学建模中应用极广绝不仅限于TSP。理解其本质后你可以将它应用到任何需要“在巨大解空间中寻找优质解”的问题上。7.1 典型适用问题类型组合优化问题旅行商问题及其变种经典应用。背包问题特别是多维背包、有依赖关系的背包。图着色问题用最少的颜色给图顶点着色相邻顶点颜色不同。调度问题车间作业调度、航班调度、课程表安排。解可以表示为工序/任务的一个排列。布局与选址问题工厂设施布局、仓库选址、基站选址。函数优化问题连续函数全局优化对于多峰、非凸的复杂函数当导数难以获取或不存在时模拟退火是一种有效的全局搜索方法。此时“解”是一个实数向量“邻域操作”可以是在当前点加上一个随机的小扰动。机器学习超参数调优可以将一组超参数如学习率、网络层数、正则化系数视为一个“解”模型在验证集上的性能如错误率作为“能量”。用模拟退火在超参数空间中进行搜索。7.2 建模竞赛中的应用步骤当你在赛题中识别出可能适用模拟退火的问题后可以按以下步骤快速实现定义解的表达形式这是最关键的一步。如何用一个数据结构如列表、数组、字典来表示问题的一个完整解例如TSP城市索引的排列列表[0, 3, 1, 2, ...]。0-1背包一个二进制列表[1,0,1,1,0,...]表示物品是否被选中。函数优化一个实数向量[x1, x2, ..., xn]。设计目标函数编写一个函数f(solution)输入一个解输出一个数值用来评价解的好坏。对于最小化问题值越小越好。确保该函数计算正确且高效。设计邻域操作设计一个或多个函数perturb(solution)能在当前解的基础上产生一个“轻微扰动”后的新解。这是算法的“探索步长”。好的邻域操作应该能连通整个解空间即从任何解出发通过有限次操作能到达任何其他解。参数化与调试使用自适应方法或经验值设置T0,T_end,alpha,L。先在小规模实例或简化问题上跑通观察优化曲线是否合理初期有波动和下降后期趋于平稳。集成与报告将算法集成到你的整体模型中。在论文中你需要清晰地描述解的表示、目标函数、邻域操作、退火策略参数设置并展示算法收敛曲线或多次运行结果的统计如最好值、最差值、平均值、标准差以证明算法的有效性和稳定性。7.3 一个更复杂的例子资源约束项目调度假设一个赛题是关于项目调度有多个任务每个任务有耗时、所需资源、前后置关系。资源总量有限。目标是找到一个任务开始时间的安排使得总工期最短且不违反资源和前后置约束。解的表达可以是一个任务序列的列表表示任务的优先顺序。再通过一个“串行调度生成方案”将序列转换为具体的开始时间。目标函数总工期最后一个任务的结束时间。同时需要在调度生成器中处理资源冲突如果序列导致资源冲突无法解决则赋予一个很大的惩罚值高能量。邻域操作随机交换两个任务的位置随机将一个任务插入到另一个位置。模拟退火尝试不同的任务顺序寻找能使总工期最短且可行的序列。这个例子比TSP复杂因为它包含了可行性约束。在模拟退火中处理约束的常用方法有惩罚函数法将约束违反程度作为一个惩罚项加到目标函数中。例如总成本 工期 M * 资源超量其中M是一个很大的正数。这样不可行解也会有很高的“能量”算法倾向于避开它们。修复法在产生新解后如果它不可行运行一个快速的“修复”程序使其变得可行然后再计算目标函数。避坑指南在数学建模论文中描述模拟退火时切忌只写“我们采用了模拟退火算法”。必须详细说明解的编码方式、邻域操作的具体设计以及关键参数的取值依据例如“初始温度设置为1000使得初始接受率约为85%”。这是评委判断你工作深度的关键。
返回列表