透過向 chatGPT-4o-mini 提問,我注意到所有爬山法可以解決的問題模擬退火都可以解決,所以爬山法死了我不想學爬山法。
具體的,對於一個多峰函式求解最值的題目都可以用模擬退火來做。
如果現在在較優解 \(x\),發現了一個新的解 \(x'\),如果 \(x'\) 比 \(x\) 優那麼 \(x\gets x'\) 否則有一定機率接受 \(x'\),這就是模擬退火的核心思想。
考慮 \(x'\) 沒有 \(x\) 優秀的機率是怎麼計算的:
令 \(\Delta x=x-x'\),那麼我們就有 \(e^{\frac{\Delta x}{T}}\) 的機率更新 \(x\),其中 \(T\) 是當前的溫度。在進行了一次操作之後就進行降溫操作,即 \(T\gets T\times 0.999\)。
下面的內容很重要!!!!!!
我們令新算出的結果為 \(f\),原本的答案為 \(lst\)。
對於求解最小值的問題,取 \(\Delta=f-lst\),那麼:
- 如果 \(\Delta<0\),那麼就直接接受。
- 否則如果
exp(-del/t)>Rand()
,那麼接受。
對於求解最小值的問題,一樣取 \(\Delta=f-lst\),那麼:
- 如果 \(\Delta>0\),那麼就直接接受。
- 否則如果
exp(del/t)>Rand()
,那麼接受。
需要注意的是 exp(x)
\(=e^x\),其中 \(x\) 就是自然函式,其影像如下:
發現對於 \(x>0\) 的情況 epx(x)
始終大於 \(1\),這個機率就是沒有意義的,所以 \(\Delta\) 的值一定是負數才有意義。
所以上面的公式在 epx
中是取 del
還是 -del
就十分好理解了,所以這並不需要死記硬背。
形象的,放一張從 OI-Wiki 偷的圖:
JSOI2004 平衡點 / 吊打XXX
練手題,但是題目太困難了,考慮給一個形式化題意:
找到一個 \((x,y)\) 使 \(\sum\limits_{i=1}^n dis((X_i,Y_i),(x,y))\times Weight_i\) 最小,輸出 \(x,y\)(可以是小數),其中 \(1\le n\le 1000\)。
就是模板,按照上面的思路寫就行了。
AHOI2014/JSOI2014 保齡球
考慮每一次隨機交換 \(x,y\) 的位置,跑模擬退火就行了。
JSOI2016 炸彈攻擊
直接隨機放炸彈的位置,因為函式長得奇醜無比所以要求擾動的範圍較大,生成的時候需要使用:
double xx=(rand()*2-RAND_MAX)*t+x;
而不是:
double xx=(2.0*rand()/RAND_MAX-1)*t+x;
HAOI2006 均分資料
考慮先隨機分組,然後模擬退火隨機改變一個元素的分組就行了。
JSOI2008 球形空間產生器
設一個變數 \(r\),表示這個高維球體的半徑,由公式 \(r=\sqrt{\sum_{i=1}^n(a_i-b_i)^2}\) 可得 \(\sum_{i=1}^n(a_i-b_i)^2= r^2\),其中 \(a_i\) 是高維球面上某一個點的座標,\(b_i\) 是球心的座標。
化簡得:
移項得:
其中 \(\sum_{i=1}^n{b_i}^2-r^2\) 與球面上的點無關,因此我們可以將其看做一個係數為 \(1\) 的變數,右邊是常量。