模擬退火
(好久沒有寫博客,一寫就是這么玄乎的東西......)
前言
- 對於這種十分神奇的近似算法
(xjb隨機算法),我一向覺得這十分不靠譜。 - 然而,只有真正認真學習過這個
(極其富有魅力)的算法的人,才知道這個算法是多么的強(多么的不靠譜) - 那么,我就簡單的介紹一下模擬退火。
算法的物理原理 (沒什么用)
- PS:以下是摘自百度百科的物理原理介紹:
模擬退火算法來源於固體退火原理,將固體加溫至充分高,再讓其徐徐冷卻,加溫時,固體內部粒子隨溫升變為無序狀,內能增大,而徐徐冷卻時粒子漸趨有序,在每個溫度都達到平衡態,最后在常溫時達到基態,內能減為最小。根據Metropolis准則,粒子在溫度T時趨於平衡的概率為e(-ΔE/(kT)),其中E為溫度T時的內能,ΔE為其改變量,k為Boltzmann常數。用固體退火模擬組合優化問題,將內能E模擬為目標函數值f,溫度T演化成控制參數t,即得到解組合優化問題的模擬退火算法:由初始解i和控制參數初值t開始,對當前解重復“產生新解→計算目標函數差→接受或舍棄”的迭代,並逐步衰減t值,算法終止時的當前解即為所得近似最優解,這是基於蒙特卡羅迭代求解法的一種啟發式隨機搜索過程。退火過程由冷卻進度表(Cooling Schedule)控制,包括控制參數的初值t及其衰減因子Δt、每個t值時的迭代次數L和停止條件S。
- 是不是發現,有點看不懂呢?甚至有一點點懵逼呢?
- 其實,這些內容沒什么太大意義只是用來看看的。
- 唯一有點用的,可能就是那個平衡概率吧。
算法在oi中的作用
- oi中存在許多無法在多項式時間內解決的問題,如經典的TSP問題, 求費馬點等多種問題。這也就是人們所熟知的np難問題。
- 人們不能忍受在指數時間內達到正確的解。因為即使解是正確的,但可能到世界毀滅,這個解也跑不出。
- 所以,人們期望有一種時間復雜度低,但是卻能得到近似解的算法。即使這個算法得出的答案可能不是完全正確的。
- 這時,模擬退火,爬山,遺傳算法,蟻群算法就漸漸到了人們的關注中,顯得尤為重要了。
- 總而言之,模擬退火的作用就是:在較短的時間內,得到十分接近的答案,或者得到的就是答案。
算法實現
- 在知乎還是哪有一個特別有趣的比喻,在一定程度上說明了爬山算法與模擬退火的實現:
- 爬山算法:兔子朝着比現在高的地方跳去。它找到了不遠處的最高山峰。但是這座山不一定是珠穆朗瑪峰。這就是爬山算法,它不能保證局部最優值就是全局最優值。
- 模擬退火:兔子喝醉了。它隨機地跳了很長時間。這期間,它可能走向高處,也可能踏入平地。但是,它漸漸清醒了並朝最高方向跳去。這就是模擬退火。
- 從以上那毫無意義的物理原理,我們可以看出,模擬退火的主要步驟有幾個:
- 設置初始溫度\(T\),初始符合條件的答案;
- 通過某種神奇的方式,找到另一個符合條件的新狀態;
- 分別將兩個狀態的答案計算出來,並作差得到\(\Delta E\)
- 根據題目要求,貪心的決定是否更換答案。即:選擇最優解。
- 如果無法替換答案,則根據一定概率替換答案。即運用到上述的平衡概率\(exp(\Delta E / T)\)隨機的決定是否替換。
- 每一次操作后,進行降溫操作。即:將溫度\(T\)乘上某一個系數,一般是\(0.985-0.999\)隨具體題目
(隨緣)定。
我們可以根據上述過程寫出一段偽代碼:
eps=1e-15;
T=初始溫度;
while(T>eps)
{
now=從當前最優狀態隨機更新的一個狀態;
delta=calc(now)-calc(ans);
if(delta與題目要求的滿足更優)ans=now;
else if(exp(delta/T)*RAND_MAX>rand())ans=now;//PS:這里的delta前面可能要加'-';
T*=t0;//t0一般在0.985-0.999之間,根據具體題目時間,隨緣調試。。。
}
- 這就是模擬退火的具體實現方式,應該代碼已經不難實現了。
- PS:有一點需要注意的是,用平衡條件進行更新答案的時候,要根據題目判斷\(\Delta E\)前要不要加\(-\),如果實在判斷不出,就兩種都試一試。如果其中一種出現特別大的答案,或很奇怪的答案,那就用另一種吧。要么就把那一行注釋掉,看看答案的變化大不大。
- 那么,模擬退火就講完了。具體的代碼實現,就通過具體的題目來看吧。
例題
( 題目打完了,還沒寫題解。最近一篇篇加進來吧。)