模擬退火 學習筆記

ly_sunrz發表於2023-01-04

模擬退火
模擬退火是一類隨機化玄學演算法,當一個問題的方案數量極大而且不是一個單峰函式時,我們常使用其求解。

而且一些最最佳化問題如果想不到正解可以用其玄學騙分(這才是重點)

退火是什麼?

退火是一種金屬熱處理工藝,指的是將金屬緩慢加熱到一定溫度,保持足夠時間,然後以適宜速度冷卻。目的是降低硬度,改善切削加工性;消除殘餘應力,穩定尺寸,減少變形與裂紋傾向;細化晶粒,調整組織,消除組織缺陷。準確的說,退火是一種對材料的熱處理工藝,包括金屬材料、非金屬材料。而且新材料的退火目的也與傳統金屬退火存在異同。 —— 百度百科

概念:

  1. 溫度(步長):每次從一個點開始隨機,溫度越大,考慮範圍越大。
    兩類:初始溫度\(T_0\),終止溫度\(T_{end}\)
  2. 衰減係數\(\lambda\):顧名思義。線性衰減效果不好,故採用指數級衰減,從零到一,越靠近一,找到正解機率越大,但也越接近無腦爆搜。

演算法步驟:
簡單來說,就是有更好的就把原來的丟了,如果沒有就以一定機率跳到另一個上。

  1. 每一次迭代,在當前範圍內隨機一個點,求出該點函式值。
  2. 比較次隨機點與當前函式值的大小關係\(\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

相關文章