化利器:模擬退火算法原理與Python實戰(zhàn)指南)
1. 項目概述為什么美賽選手必須掌握模擬退火如果你正在為美國大學(xué)生數(shù)學(xué)建模競賽MCM/ICM俗稱“美賽”做準(zhǔn)備并且已經(jīng)刷過一些往年的O獎、F獎?wù)撐哪銜l(fā)現(xiàn)一個高頻出現(xiàn)的詞Heuristic Algorithm也就是啟發(fā)式算法。而在眾多啟發(fā)式算法中模擬退火算法絕對是出場率最高的明星選手之一。它不像遺傳算法那樣需要復(fù)雜的編碼和種群操作也不像粒子群算法那樣有多個參數(shù)需要精細(xì)調(diào)校。模擬退火以其簡潔的框架、強大的全局搜索能力和易于實現(xiàn)的特性成為了解決美賽中那些復(fù)雜、非線性、多峰優(yōu)化問題的“瑞士軍刀”。簡單來說模擬退火算法是一種受物理中固體退火過程啟發(fā)而得到的優(yōu)化算法。它的核心思想是在搜索過程中以一定的概率接受比當(dāng)前解更差的“壞解”從而避免陷入局部最優(yōu)最終隨著“溫度”的降低逐漸穩(wěn)定到全局最優(yōu)解附近。這個“以一定概率接受壞解”的機制是它跳出局部最優(yōu)陷阱的關(guān)鍵。在美賽的賽題里無論是設(shè)計最優(yōu)的交通路線、分配有限的救援資源、還是優(yōu)化復(fù)雜的供應(yīng)鏈網(wǎng)絡(luò)你面對的幾乎都是一個沒有顯式數(shù)學(xué)表達式、或者表達式極其復(fù)雜、變量眾多的“黑箱”優(yōu)化問題。傳統(tǒng)的梯度下降法在這里基本失靈而模擬退火則能大顯身手。我參加過幾次美賽也輔導(dǎo)過不少隊伍一個深刻的體會是很多隊伍知道模擬退火這個名字也能在論文里寫上一段原理介紹但一到實際編碼和調(diào)參就抓瞎。要么是算法根本收斂不到一個合理的解要么是運行效率低下在短短四天賽期內(nèi)無法完成足夠的迭代。這篇文章我就結(jié)合自己踩過的坑和成功的經(jīng)驗帶你從零開始徹底吃透模擬退火算法并手把手教你用Python實現(xiàn)一個魯棒、高效、易調(diào)整的SA框架讓你在美賽中遇到優(yōu)化問題時能真正把它用起來而不是僅僅停留在“提及”的層面。2. 模擬退火核心原理與美賽應(yīng)用場景拆解2.1 物理退火與算法思想的映射要理解模擬退火先得搞懂它模仿的物理過程——金屬退火。將金屬加熱到高溫其內(nèi)部粒子會處于高能無序狀態(tài)。然后緩慢降溫退火粒子逐漸趨于有序最終在常溫下達到能量最低的穩(wěn)定晶體結(jié)構(gòu)。如果降溫太快淬火粒子來不及重新排列就會停留在能量較高的非晶態(tài)。算法完美地映射了這一過程解的狀態(tài)對應(yīng)金屬的微觀狀態(tài)。目標(biāo)函數(shù)值成本對應(yīng)系統(tǒng)的能量。我們的目標(biāo)是找到成本最低的解。溫度是一個關(guān)鍵的控制參數(shù)它決定了算法接受“壞解”的概率。退火策略即溫度如何隨時間下降的 schedule。算法的精髓在于Metropolis 準(zhǔn)則它給出了從當(dāng)前解S_old跳轉(zhuǎn)到新解S_new的接受概率P如果 ΔE E_new - E_old 0 (新解更優(yōu))則 P 1無條件接受。 如果 ΔE 0 (新解更差)則 P exp(-ΔE / T)其中 T 是當(dāng)前溫度。這個公式是理解一切的關(guān)鍵。當(dāng)溫度T很高時即使ΔE很大即解差很多exp(-ΔE / T)也可能接近1算法幾乎完全隨機游走廣泛探索解空間。隨著T逐漸降低接受差解的概率越來越小算法越來越傾向于“下山”最終在低溫時穩(wěn)定在一個局部期望是全局最優(yōu)解附近。2.2 美賽典型問題與SA的適配性分析模擬退火在美賽中并非萬能但在以下幾類問題中表現(xiàn)尤為出色組合優(yōu)化問題這是SA的傳統(tǒng)強項。例如旅行商問題規(guī)劃最優(yōu)巡檢路線、物流配送路徑。美賽2016年B題太空垃圾中的碎片收集路徑規(guī)劃其本質(zhì)就是一個復(fù)雜的TSP變種。調(diào)度與排班問題如醫(yī)院手術(shù)室調(diào)度、航班調(diào)度。2018年D題電動汽車充電站就涉及到充電樁的調(diào)度優(yōu)化。資源分配問題在多個候選點中選擇最優(yōu)位置設(shè)施選址或分配有限的資金、物資。2021年C題黃蜂巢中關(guān)于數(shù)據(jù)特征的篩選和權(quán)重分配就可以轉(zhuǎn)化為一個組合優(yōu)化問題。連續(xù)函數(shù)優(yōu)化當(dāng)決策變量是連續(xù)值且目標(biāo)函數(shù)多峰、非線性、不可微時。例如參數(shù)擬合用一個復(fù)雜模型去擬合數(shù)據(jù)需要優(yōu)化模型參數(shù)。設(shè)計優(yōu)化設(shè)計某個產(chǎn)品如翼型、天線的形狀參數(shù)使某項性能指標(biāo)最優(yōu)?;旌险麛?shù)規(guī)劃部分變量是整數(shù)如選擇與否部分變量是連續(xù)值。SA可以靈活處理這種混合類型。為什么SA適合美賽模型自由SA不要求目標(biāo)函數(shù)可導(dǎo)、連續(xù)甚至不要求你能寫出顯式表達式。你只需要一個能評估任意給定解好壞的“評價函數(shù)”即可。這在處理現(xiàn)實世界復(fù)雜問題時極其有利。實現(xiàn)快速核心代碼可能只需幾十行。在分秒必爭的美賽期間能快速實現(xiàn)一個可用的算法原型至關(guān)重要??山忉屝詮娢锢眍惐壬鷦尤菀自谡撐闹嘘U述評委也熟悉。靈活可調(diào)你可以很容易地將各種約束條件如時間窗、容量限制通過懲罰函數(shù)的方式融入目標(biāo)函數(shù)中。注意SA的缺點是通常不能保證找到全局最優(yōu)解且其性能嚴(yán)重依賴于參數(shù)設(shè)置退火計劃表。在論文中你需要說明你進行了多次獨立運行以增加找到好解的信心并展示參數(shù)選擇的合理性。3. 算法實現(xiàn)核心一個魯棒的Python框架構(gòu)建理解了原理我們來動手實現(xiàn)。我們不直接調(diào)用現(xiàn)成的庫如simanneal而是從零構(gòu)建。只有自己實現(xiàn)一遍你才能真正掌控它并在論文中游刃有余地解釋你的算法設(shè)計。3.1 問題定義與解的表達首先我們必須將美賽問題“翻譯”成SA算法能處理的形式。我們以一個經(jīng)典的旅行商問題為例有10個城市需要找一條最短的環(huán)路訪問每個城市一次。解的表達一個解就是城市的一個排列Permutation。例如[0, 3, 1, 9, 2, 5, 8, 7, 4, 6]。目標(biāo)函數(shù)計算這個排列所對應(yīng)路徑的總距離。距離可以來自真實的經(jīng)緯度坐標(biāo)也可以是一個給定的距離矩陣。import numpy as np import math import random # 假設(shè)我們隨機生成10個城市的坐標(biāo) num_cities 10 cities np.random.rand(num_cities, 2) * 100 # 坐標(biāo)在[0,100)區(qū)間 # 計算距離矩陣方便后續(xù)調(diào)用 def calculate_distance_matrix(points): n len(points) dist_mat np.zeros((n, n)) for i in range(n): for j in range(n): if i ! j: dist_mat[i][j] np.linalg.norm(points[i] - points[j]) # 歐氏距離 return dist_mat distance_matrix calculate_distance_matrix(cities) # 目標(biāo)函數(shù)計算一條路徑的總長度 def total_distance(path, dist_mat): 計算給定路徑的總距離 total 0.0 n len(path) for i in range(n): j (i 1) % n # 形成環(huán)路最后一個城市連回第一個 total dist_mat[path[i]][path[j]] return total3.2 鄰域結(jié)構(gòu)與新解生成鄰域結(jié)構(gòu)定義了如何從當(dāng)前解產(chǎn)生一個“鄰居”解。不同的問題需要設(shè)計不同的鄰域操作。對于TSP常用的有交換隨機選擇兩個位置交換其城市。逆轉(zhuǎn)隨機選擇一段子路徑將其順序反轉(zhuǎn)。插入隨機選擇一個城市將其插入到另一個隨機位置。我們選擇逆轉(zhuǎn)操作因為它通常能產(chǎn)生更好的探索效果。def generate_neighbor(path): 通過逆轉(zhuǎn)一段子路徑來生成鄰居解 n len(path) new_path path.copy() # 重要必須復(fù)制避免修改原解 # 隨機選擇兩個不同的索引 i, j random.sample(range(n), 2) i, j min(i, j), max(i, j) # 逆轉(zhuǎn) i 到 j 之間的片段 new_path[i:j1] reversed(new_path[i:j1]) return new_path3.3 退火計劃表算法性能的靈魂這是調(diào)參的核心直接決定算法成敗。一個完整的退火計劃表包括初始溫度T0要足夠高使得幾乎所有移動都被接受接受率 ~1。一個經(jīng)驗方法是進行少量隨機游走計算目標(biāo)函數(shù)值的標(biāo)準(zhǔn)差σ然后設(shè)T0 k * σk是一個較大的數(shù)如10, 100。更簡單的方法是設(shè)T0使得初始接受概率約為0.8。我們可以通過一個簡短的熱身過程來估計。def estimate_initial_temperature(path, dist_mat, iterations1000): 估算初始溫度使得初始接受率約為0.8 delta_es [] current_energy total_distance(path, dist_mat) for _ in range(iterations): new_path generate_neighbor(path) new_energy total_distance(new_path, dist_mat) delta_e new_energy - current_energy if delta_e 0: # 只關(guān)心變差的情況 delta_es.append(delta_e) # 更新當(dāng)前路徑繼續(xù)隨機游走 path new_path current_energy new_energy if delta_es: # 我們希望 exp(-ΔE_avg / T0) 0.8 T0 -ΔE_avg / ln(0.8) avg_delta_e np.mean(delta_es) t0 -avg_delta_e / math.log(0.8) return max(t0, 1e-4) # 避免為0或負(fù)數(shù) else: # 如果所有移動都是變好說明初始解很差溫度可以設(shè)低一點 return 100.0溫度更新函數(shù)最常用的是指數(shù)衰減T_{k1} α * T_k其中α是衰減系數(shù)通常取0.8 ~ 0.99。值越大降溫越慢搜索越充分但耗時越長。馬爾可夫鏈長度L在每個溫度下迭代的次數(shù)。通常與問題規(guī)模相關(guān)例如L 100 * n(n為城市數(shù))。也可以動態(tài)調(diào)整比如直到在該溫度下解的狀態(tài)分布穩(wěn)定。終止溫度T_end或終止條件可以設(shè)一個很小的值如1e-7或者連續(xù)若干個溫度下最優(yōu)解都沒有改進時停止。3.4 核心算法流程實現(xiàn)將以上所有部分組合起來形成完整的算法框架。def simulated_annealing(initial_path, dist_mat, t0None, alpha0.95, max_iter10000, t_end1e-7): 模擬退火主函數(shù) 參數(shù): initial_path: 初始解路徑 dist_mat: 距離矩陣 t0: 初始溫度若為None則自動估計 alpha: 溫度衰減系數(shù) max_iter: 最大迭代次數(shù)安全停止條件 t_end: 終止溫度 返回: best_path: 找到的最佳路徑 best_energy: 最佳路徑長度 history: 記錄迭代過程中的能量和溫度用于繪圖分析 current_path initial_path.copy() current_energy total_distance(current_path, dist_mat) best_path current_path.copy() best_energy current_energy if t0 is None: t estimate_initial_temperature(current_path, dist_mat) else: t t0 iteration 0 history {temp: [], energy: [], best_energy: []} while t t_end and iteration max_iter: # 每個溫度下的迭代次數(shù)這里簡單設(shè)為問題規(guī)模的倍數(shù) l len(current_path) * 10 for _ in range(l): # 生成鄰居 new_path generate_neighbor(current_path) new_energy total_distance(new_path, dist_mat) delta_e new_energy - current_energy # Metropolis 準(zhǔn)則 if delta_e 0 or random.random() math.exp(-delta_e / t): current_path new_path current_energy new_energy # 更新歷史最優(yōu) if current_energy best_energy: best_path current_path.copy() best_energy current_energy # 記錄數(shù)據(jù) history[temp].append(t) history[energy].append(current_energy) history[best_energy].append(best_energy) # 降溫 t * alpha iteration 1 # 可選增加一個早停機制如果連續(xù)N個溫度最優(yōu)解未改進則停止 # ... print(f迭代結(jié)束: 最終溫度 {t:.2e}, 迭代次數(shù) {iteration}) print(f最優(yōu)路徑長度: {best_energy:.4f}) return best_path, best_energy, history3.5 可視化與結(jié)果分析在美賽論文中圖表是必不可少的。我們需要可視化算法的收斂過程和最終結(jié)果。import matplotlib.pyplot as plt # 生成初始解隨機排列 initial_path list(range(num_cities)) random.shuffle(initial_path) print(f初始隨機路徑長度: {total_distance(initial_path, distance_matrix):.4f}) # 運行模擬退火 best_path, best_energy, history simulated_annealing( initial_path, distance_matrix, t0None, alpha0.98, max_iter500, t_end1e-5 ) # 繪制收斂曲線 fig, (ax1, ax2) plt.subplots(1, 2, figsize(12, 4)) # 圖1能量隨迭代的變化 ax1.plot(history[energy], b-, alpha0.6, label當(dāng)前能量) ax1.plot(history[best_energy], r-, linewidth1.5, label歷史最優(yōu)能量) ax1.set_xlabel(迭代次數(shù)) ax1.set_ylabel(路徑長度) ax1.set_title(模擬退火收斂過程) ax1.legend() ax1.grid(True, linestyle--, alpha0.5) # 圖2最終路徑圖 ax2.scatter(cities[:, 0], cities[:, 1], cred, s100, zorder5) for i, (x, y) in enumerate(cities): ax2.text(x1, y1, str(i), fontsize9) # 繪制路徑 for i in range(num_cities): start_city best_path[i] end_city best_path[(i1) % num_cities] ax2.plot([cities[start_city, 0], cities[end_city, 0]], [cities[start_city, 1], cities[end_city, 1]], b-, linewidth1, alpha0.7) ax2.set_xlabel(X坐標(biāo)) ax2.set_ylabel(Y坐標(biāo)) ax2.set_title(f最優(yōu)路徑 (總長度: {best_energy:.2f})) ax2.grid(True, linestyle--, alpha0.3) ax2.axis(equal) plt.tight_layout() plt.show()運行這段代碼你會看到兩張圖一張展示了算法過程中當(dāng)前解和最優(yōu)解的變化可以看到在高溫時能量波動劇烈隨著溫度降低逐漸穩(wěn)定另一張展示了找到的最優(yōu)訪問路徑。4. 美賽實戰(zhàn)調(diào)參與性能優(yōu)化策略紙上得來終覺淺絕知此事要躬行。一個能跑通的SA框架只是開始要想在美賽中真正用好它必須掌握調(diào)參和優(yōu)化的技巧。這部分是論文中體現(xiàn)你建模深度和實驗嚴(yán)謹(jǐn)性的關(guān)鍵。4.1 參數(shù)敏感性分析與系統(tǒng)調(diào)參SA的性能對參數(shù)非常敏感。你不能在論文里寫“我們設(shè)置了α0.95因為這是常用值”。你需要證明你的參數(shù)選擇是合理的。系統(tǒng)調(diào)參步驟固定其他參數(shù)單變量分析初始溫度T0設(shè)置過低會導(dǎo)致過早陷入局部最優(yōu)過高則浪費計算時間。使用前面提到的estimate_initial_temperature函數(shù)是一個好方法并在論文中說明。衰減系數(shù)α在[0.8, 0.999]之間測試。較小的α降溫快適合簡單問題或時間緊迫較大的α搜索更充分但耗時??梢岳L制不同α下“最優(yōu)解隨迭代次數(shù)變化”的曲線進行對比。馬爾可夫鏈長度L通常與問題規(guī)模n成正比??梢詼y試L 50*n, 100*n, 200*n。一個經(jīng)驗法則是在每個溫度下應(yīng)使解有足夠的機會達到準(zhǔn)平衡狀態(tài)。設(shè)計正交實驗如果你時間充裕在美賽中這很奢侈可以對(T0, α, L)進行網(wǎng)格搜索或使用更高級的調(diào)參方法如貝葉斯優(yōu)化找到在平均意義下表現(xiàn)最好的參數(shù)組合。定義評價指標(biāo)不僅僅是最終找到的解的質(zhì)量最優(yōu)值還要考慮穩(wěn)定性多次獨立運行結(jié)果的標(biāo)準(zhǔn)差和收斂速度達到某個滿意解所需的迭代次數(shù)或時間。在論文中的呈現(xiàn)方式制作一個參數(shù)敏感性表格或一組對比曲線圖。例如參數(shù)組合 (T0, α, L)平均最優(yōu)解標(biāo)準(zhǔn)差平均運行時間(s)備注(估計值, 0.90, 100*n)342.515.212.3收斂快但解不穩(wěn)定(估計值, 0.98, 100*n)328.75.145.8解質(zhì)量高且穩(wěn)定推薦(估計值, 0.98, 200*n)327.94.889.6解略優(yōu)但耗時翻倍性價比低4.2 高級優(yōu)化技巧提升效率與效果自適應(yīng)退火計劃表自適應(yīng)鏈長如果在一個溫度下接受了足夠多的移動例如超過0.5*L次可以提前進入下一個溫度如果接受率太低可以延長鏈長或在該溫度多迭代一會兒。自適應(yīng)降溫根據(jù)當(dāng)前解的接受率動態(tài)調(diào)整α。如果接受率太高說明降溫太慢可以加大α更快降溫反之則減小α。領(lǐng)域操作的改進與混合不要只使用一種鄰域操作??梢噪S機混合使用交換、逆轉(zhuǎn)、插入甚至設(shè)計針對特定問題的大鄰域搜索操作。在低溫階段可以切換到更精細(xì)的、擾動更小的鄰域操作進行局部微調(diào)。記憶與重啟機制記憶最優(yōu)解我們的基礎(chǔ)框架已經(jīng)實現(xiàn)了。重啟策略如果連續(xù)多個溫度最優(yōu)解都沒有改善可以保存當(dāng)前最優(yōu)解然后從另一個隨機初始解或以當(dāng)前最優(yōu)解為基礎(chǔ)進行較大擾動重新開始退火過程。這能有效避免陷入深度的局部最優(yōu)。目標(biāo)函數(shù)計算的優(yōu)化這是最大的性能瓶頸。對于TSP當(dāng)我們進行逆轉(zhuǎn)操作時不需要重新計算整條路徑的長度。只需要計算發(fā)生變化的邊。例如逆轉(zhuǎn)了路徑中從索引i到j(luò)的段總距離的變化只與邊(i-1, i),(j, j1)舊邊和(i-1, j),(i, j1)新邊有關(guān)。實現(xiàn)這種增量計算可以將每次評估的時間復(fù)雜度從O(n)降到O(1)。def total_distance_incremental(old_path, old_distance, i, j, dist_mat): 增量計算逆轉(zhuǎn)操作后的新距離 n len(old_path) # 獲取受影響的城市索引 a, b old_path[(i-1) % n], old_path[i] c, d old_path[j], old_path[(j1) % n] # 舊邊距離 old_edge_sum dist_mat[a][b] dist_mat[c][d] # 新邊距離 (逆轉(zhuǎn)后b和c的位置互換) new_edge_sum dist_mat[a][c] dist_mat[b][d] # 新總距離 new_distance old_distance - old_edge_sum new_edge_sum return new_distance在generate_neighbor函數(shù)中可以同時返回新路徑和計算好的新距離避免在SA主循環(huán)中重復(fù)計算整個路徑的距離。這個優(yōu)化對于大規(guī)模問題城市數(shù)100是至關(guān)重要的。5. 從TSP到美賽真實問題建模與適配實戰(zhàn)掌握了TSP這個經(jīng)典案例我們來看看如何將SA應(yīng)用到更貼近美賽的真實問題中。關(guān)鍵在于問題建模和解的表達。5.1 案例一設(shè)施選址問題2018 MCM Problem D問題簡化在某個區(qū)域內(nèi)有若干需求點需要選擇k個位置建立充電站使得所有需求點到其最近充電站的距離之和最小。解的表達一個長度為k的列表每個元素是選中的候選站點的ID。例如[3, 15, 7, 22]表示選擇了第3、15、7、22號候選點。目標(biāo)函數(shù)對于每個需求點計算其到解列表中所有站點的最小距離。將這些最小距離求和。可選如果存在容量、建設(shè)成本等約束可以將其作為懲罰項加到總距離上總成本 總距離 λ * 違反約束的懲罰。鄰域操作替換隨機選擇一個已選站點將其替換為一個未選站點。交換隨機交換一個已選站點和一個未選站點。注意事項需要維護一個“需求點-最近站點”的映射增量更新時只需更新受站點變更影響的需求點可以極大提升效率。5.2 案例二多目標(biāo)優(yōu)化問題2021 ICM Problem E很多美賽問題不是單一目標(biāo)而是需要平衡多個目標(biāo)如成本最低、覆蓋最廣、公平性最好。SA可以很容易地擴展到多目標(biāo)優(yōu)化。常用方法加權(quán)和法將多個目標(biāo)f1(x), f2(x), ...通過權(quán)重w1, w2, ...組合成一個標(biāo)量目標(biāo)函數(shù)F(x) w1*f1(x) w2*f2(x) ...然后對這個F(x)使用標(biāo)準(zhǔn)的SA進行優(yōu)化。權(quán)重的選擇反映了你對不同目標(biāo)的偏好。在論文中的處理說明你意識到問題的多目標(biāo)特性。解釋采用加權(quán)和法的原因簡單有效易于與SA結(jié)合。進行敏感性分析展示不同權(quán)重組合下得到的最優(yōu)解有何不同可以制作一個表格或帕累托前沿圖。這能極大地豐富你論文的分析維度。# 假設(shè)有兩個目標(biāo)成本Cost和覆蓋人口Coverage覆蓋越大越好 def multi_objective_function(solution): cost calculate_cost(solution) coverage calculate_coverage(solution) # 將覆蓋轉(zhuǎn)化為需要最小化的形式例如 負(fù)覆蓋 或 未覆蓋率 # 使用權(quán)重進行加權(quán) w1, w2 0.7, 0.3 # 權(quán)重需要根據(jù)問題意義設(shè)定 return w1 * cost - w2 * coverage # 假設(shè)我們要最小化這個值5.3 整合到美賽論文的要點算法描述部分不要只貼代碼。用流程圖或偽代碼清晰地展示你的SA框架并輔以文字說明關(guān)鍵步驟初始化、鄰域生成、Metropolis準(zhǔn)則、降溫、終止。參數(shù)設(shè)置部分詳細(xì)說明每個參數(shù)T0, α, L, T_end是如何確定的。引用你的調(diào)參實驗“如表1所示”。結(jié)果分析部分展示算法收斂圖證明其有效性。匯報多次獨立運行的最佳結(jié)果、平均結(jié)果和標(biāo)準(zhǔn)差證明算法的穩(wěn)定性。如果可能與基準(zhǔn)方法對比例如與貪婪算法、隨機搜索的結(jié)果對比突出SA的優(yōu)越性。對得到的最優(yōu)解進行業(yè)務(wù)解讀。例如“我們的模型建議在A、B、C三地建立充電站該方案能在控制成本的前提下覆蓋90%的高需求區(qū)域”。靈敏度分析部分如前所述對關(guān)鍵參數(shù)和模型假設(shè)如多目標(biāo)權(quán)重進行靈敏度分析展示結(jié)果的魯棒性。6. 常見陷阱、調(diào)試技巧與備選方案即使框架正確在實際編碼和運行中你也會遇到各種問題。這里分享一些“踩坑”經(jīng)驗。6.1 算法不收斂或收斂到差解癥狀最優(yōu)解曲線一直上下跳動沒有穩(wěn)定下降的趨勢或者很快陷入一個很差的解。排查與解決檢查初始溫度用estimate_initial_temperature函數(shù)輸出初始溫度值并打印初始接受概率。如果初始接受概率遠(yuǎn)低于0.5說明溫度太低了。檢查鄰域操作你的鄰域操作是否產(chǎn)生了“合法”的解對于TSP逆轉(zhuǎn)操作永遠(yuǎn)產(chǎn)生合法排列。但對于其他問題如背包問題要求總重量不超過容量隨機生成的鄰居可能非法。你需要設(shè)計能保持解合法性的鄰域操作或者使用懲罰函數(shù)法。檢查目標(biāo)函數(shù)確保你的目標(biāo)函數(shù)計算是正確的。用一個非常簡單的、你知道最優(yōu)解的例子來驗證。例如對于TSP如果所有城市在一條直線上最優(yōu)路徑長度應(yīng)該是很容易手動計算的。放緩降溫速度大幅提高衰減系數(shù)α如從0.95調(diào)到0.995并增加馬爾可夫鏈長度L。這會給算法更多的探索時間。引入重啟機制當(dāng)最優(yōu)解超過N次迭代未更新時從當(dāng)前最優(yōu)解加入一個較大擾動后重新開始退火。6.2 算法運行速度太慢癥狀迭代幾千次就需要幾分鐘甚至更久。排查與解決性能分析使用Python的cProfile或line_profiler工具找出代碼中最耗時的函數(shù)。99%的情況下瓶頸都在目標(biāo)函數(shù)評估上。實現(xiàn)增量計算如前面TSP例子所示對于特定的鄰域操作實現(xiàn)目標(biāo)函數(shù)的增量更新避免每次O(n)的全量計算。向量化計算如果目標(biāo)函數(shù)涉及大量數(shù)值運算盡量使用NumPy的向量化操作避免Python層面的for循環(huán)。降低鏈長L在調(diào)參允許的范圍內(nèi)適當(dāng)減少每個溫度下的迭代次數(shù)??梢試L試自適應(yīng)鏈長。使用更快的鄰域操作有些鄰域操作計算新解的成本更低。例如對于TSP“交換兩個城市”比“逆轉(zhuǎn)一段路徑”計算增量更簡單。6.3 與其他算法的對比與選擇SA不是唯一的啟發(fā)式算法。在美賽中根據(jù)問題特點選擇合適的算法很重要。遺傳算法更適合解空間巨大、解可以用染色體二進制串、序列自然編碼的問題。它通過種群并行搜索探索能力可能更強但參數(shù)更多種群大小、交叉率、變異率實現(xiàn)更復(fù)雜。粒子群算法更適合連續(xù)空間的優(yōu)化問題。概念簡單參數(shù)較少但對于離散組合問題需要特殊處理。禁忌搜索通過一個“禁忌表”禁止近期訪問過的解強制探索新區(qū)域。對于某些問題效率很高但需要設(shè)計候選列表和禁忌策略。我的建議對于首次參加美賽或編程經(jīng)驗不多的隊伍模擬退火是首選。它原理簡單實現(xiàn)快速參數(shù)相對直觀容易在論文中解釋清楚。你可以先實現(xiàn)SA作為基線模型如果時間允許再嘗試將其與局部搜索如每次接受新解后都進行一段貪婪下降結(jié)合形成模擬退火局部搜索的混合算法效果往往會有提升。最后記住美賽的核心是解決問題并清晰地表達你的思路。模擬退火是你工具箱里一件強大的武器但比武器本身更重要的是你如何運用它去分析問題、構(gòu)建模型、解釋結(jié)果。把這套代碼和理解吃透當(dāng)你看到賽題中出現(xiàn)“optimization”、“minimize”、“maximize”、“best schedule”這些詞時你就能自信地知道你的SA框架已經(jīng)準(zhǔn)備好了。