算法:模擬退火

之前覺得模擬退火算法是很高大上的存在,一直沒有去了解。然後上次數模校賽我們就用到了模擬退火算法,發現思路其實並不複雜。

模擬退火算法

模擬退火(Simulated Annealing),來源於熱力學上的退火現象。退火現象就是,將固體加溫再徐徐冷卻,最後在常溫時就會呈現晶體狀態。從微觀角度來看,固體加溫時,內部粒子趨於無序,內能增大;徐徐冷卻時,粒子趨於有序,內能減小,在每個溫度都達到平衡態;最後在常溫時達到基態,此時內能減到最小。

其實退火現象只是算法思路的來源,用物理學的原理是無法解釋算法的。從算法的角度來看,模擬退火算法是用於解決優化問題的算法。優化問題即滿足題目約束的條件下求最優解的問題,常用的思路有廣度優先搜索、貪心、動態規劃等。不過當一個優化問題規模很大時,要找到最優解幾乎是不可能的,所以我們只能去找儘可能接近最優的解。如果用一般的思路求解,往往會陷入局部最優,而模擬退火算法可以避免這個問題。局部最優解相當於函數的極小值,全局最優解相當於函數的最小值,顯然,全局最優解纔是我們的目標。

模擬退火算法的思路模仿了退火原理。首先選取一個初始解,然後迭代更新,最後得到最優解。每次迭代都要先用舊解得到新解,再作比較,若新解更優,則用新解代替舊解;否則,以一定概率替換舊解。也就是說,每次迭代都趨於得到一個更優的解,最後自然會得到一個接近最優的解。不過,當舊解更優時,新解仍然有一定概率替換舊解,這樣算法就有了一定的隨機性,即使舊解是局部最優,新解也有機會跳出去。考慮到隨着迭代次數的增加,舊解已經越來越接近最優了,這時就應該減小新解跳出舊解的概率。

代碼

const Solution DOMAIN;
const double INIT_T = 100;
const double MIN_T = 1;
const double RATE = 0.98;
const int LOOP = 1000;

/**
  * @return: the initialized solution
  */
Solution init();

/**
  * @param s: the old solution
  * @param domain: the domain of solution
  * @return: the new solution
  */
Solution getNext(Solution s, Solution domain);

void sa() {
  Solution s = init();
  double t = INIT_T;
  while (t > MIN_T) {
    for (int i = 0; i < LOOP; ++i) {
      Solution next = getNext(s, DOMAIN);
      if (next < s) s = next;
      else {
        double p = exp((s - next)/t);
        if (rand() / (RAND_MAX + 1) < p) s = next;
      }
    }
    t *= RATE;
  }
}

參考資料

  1. 百度百科
    https://baike.baidu.com/item/模擬退火算法/355508?fr=aladdin
  2. 博客
    https://www.cnblogs.com/ranjiewen/p/6084052.html
    https://blog.csdn.net/AI_BigData_wh/article/details/77943787?locationNum=2&fps=1
    https://blog.csdn.net/qq_30981697/article/details/70032094?locationNum=9&fps=1
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章