模擬退火是一類隨機化玄學演算法,當一個問題的方案數量極大而且不是一個單峰函式時,我們常使用其求解。
而且一些最最佳化問題如果想不到正解可以用其玄學騙分(這才是重點)
退火是什麼?
退火是一種金屬熱處理工藝,指的是將金屬緩慢加熱到一定溫度,保持足夠時間,然後以適宜速度冷卻。目的是降低硬度,改善切削加工性;消除殘餘應力,穩定尺寸,減少變形與裂紋傾向;細化晶粒,調整組織,消除組織缺陷。準確的說,退火是一種對材料的熱處理工藝,包括金屬材料、非金屬材料。而且新材料的退火目的也與傳統金屬退火存在異同。 —— 百度百科
概念:
- 溫度(步長):每次從一個點開始隨機,溫度越大,考慮範圍越大。
兩類:初始溫度\(T_0\),終止溫度\(T_{end}\) - 衰減係數\(\lambda\):顧名思義。線性衰減效果不好,故採用指數級衰減,從零到一,越靠近一,找到正解機率越大,但也越接近無腦爆搜。
演算法步驟:
簡單來說,就是有更好的就把原來的丟了,如果沒有就以一定機率跳到另一個上。
- 每一次迭代,在當前範圍內隨機一個點,求出該點函式值。
- 比較次隨機點與當前函式值的大小關係\(\Delta=f_{new}-f_{present}\)
- 情況\(1\): \(\Delta <0\),跳到新點上。
- 情況\(2\): \(\Delta >0\),以一定機率(\(e^{-\frac{\Delta}{T}}\))跳到新點上。
為了更接近正解,減小誤差,可以多跑幾次。
code
void simulate_anneal()
{
PDD cur(rand(0,10000),rand(0,10000));
for(double t=1e4;t>1e-4;t*=0.99)
{
PDD np(rand(cur.x-t,cur.x+t),rand(cur.y-t,cur.y+t));
double dt=calc(np)-calc(cur);
if(exp(-dt/t)>rand(0,1)) cur=np;
}
}
習題選做:
P1337 【JSOI2004】 平衡點 / 吊打XXX
P2503 【HAOI2006】 均分資料
P4035 【JSOI2008】 球形空間產生器
P3878 【TJOI2010】分金幣
P4274 【NOI2004】 小H的小屋
P5544 【JSOI2016】 炸彈攻擊1