模拟退火

总结

\(\quad\)模拟退火的基本思路就是,如果状态更优,那么就接受他,如果结果不更优,那么以 \(\frac{-\Delta E}{T},\Delta E\geq0\) 的概率去接受当前值。

\(\quad\)要注意的是:

  1. 接受一个不那么优的值时,不要改变全局答案和答案相关变量,仅仅改变当前相关值。

  2. 对于温度和下降系数的设置要设置好,一个比较优秀的数字是 5000 0.996

  3. 最好卡时优化

  4. 可以尝试在多段区间分别退火,最后取一个最优值

  5. 每一次退火前答案相关变量的取值就取之前已经得到了的最优值

  6. 对于这个概率可以这么表示 \(P*RAND\_MAX>rand()\)

  7. 对于每一次当前值的变化可以考虑加入 T 的影响(尤其是在实数中),这样温度越低时,当前值浮动的幅度就会越小。

  8. 最好设一个接近答案的初始值

  9. 这一类题目一般题目的范围回比较小(一般控制在几十)

\(\quad\)上述的都是模拟退火的套路东西,对于一个题目,如果考虑好了模拟退火,那么真正要思考的是每次当前值的变化应该怎么设置(正负变化?),一个状态优劣的价值如何衡量和初始值的设置(一般取平均数)。

Luogu P1337 [JSOI2004]平衡点 / 吊打XXX

\(\quad\)如果一个坐标满足所以目标位置到它的距离乘上目标位置的重量的和最小,那么就最优。每次值的变化就 \(+T*(rand()*2-RAND \_ MAX)\) ,之所以这样设计是因为变换的值要有正有负。初始数就是取平均数。

void fire(){
    db T=5000,down=0.996;
    db dx=ansx,dy=ansy;
    while(T>1e-15){
         db x=dx+T*(rand()+rand()-RAND_MAX);
         db y=dy+T*(rand()+rand()-RAND_MAX);
         db d=calc(x,y);
         if(d-ans<0) ans=d,dx=x,dy=y,ansx=dx,ansy=dy;
         else if(exp((ans-d)/T)*RAND_MAX>rand()) dx=x,dy=y;
         T=T*down;
    }
}

Luogu P2503 [HAOI2006]均分数据

\(\quad\)状态的价值已经设置好了,那么考虑初始状态,可以按顺序每次将当前物品放到组和最小的组中,那么我们可以通过打乱数列的顺序以此达到不同的组合,那么每次随机两个改变位置的数字。

Luogu P3878 [TJOI2010]分金币

\(\quad\)和上组差不多的思想,默认前半的数组为一组,剩下的为一组,通过打乱顺序达到不同的组合。

posted @ 2022-06-18 18:14  Kzos_017  阅读(49)  评论(0编辑  收藏  举报