模拟退火

模拟退火((SA))和随机化贪心

物理上的模拟退火

固体退火原理,将固体加温至充分高,再让其徐徐冷却,加温时,固体内部粒子随温升变为无序状,内能增大,而徐徐冷却时粒子渐趋有序,在每个温度都达到平衡态,最后在常温时达到基态,内能减为最小。

启发

根据物理上的模拟退火,我们可以吸取一些经验,采用模拟退火的方法。

模拟退火是一个非常优秀的骗分甚至可以秒杀正解的算法,其能够很好地通过每次时间复杂度很小的贪心,然后不停贪心,就算这样那贪心许多次之后时间复杂度依然很小,甚至可以秒杀正解,而且模拟退火是有变化幅度的,而算法性能和其结果与初始值有关是他的特点,既是它的优点也是它的缺点。优点在于你可以控制它的复杂度,但缺点也就是该算法容易被卡。所以随机化贪心要少用啊。不然人品就败光了。

过程

  1. 初始化:初始温度(T)(充分大),初始解状态(S)(是算法迭代的起点)

  2. 产生新解(S′)

  3. 计算增量(Δt′=C(S′)-C(S)),其中(C(S))为评价函数

  4. (Δt′<0)则接受(S′)作为新的当前解,否则以概率(exp(-Δt′/T))接受(S′)作为新的当前解.

  5. 如果满足终止条件或温度过低则输出当前解作为最优解,结束程序。终止条件通常取为连续若干个新解都没有被接受时终止算法。

  6. (T)逐渐减少,且(T>=0),然后转第(2)步。

思想

其思想主要结合了退火和信息学的特点,采取模拟的算法来实现随机化贪心,有人这么比喻,

(Code)([JSOI2004]平衡点)

#include <bits/stdc++.h>
#pragma GCC optimize(2)
#pragma GCC optimize(3)
const double eps = 1e-253;
const double t = 0.99389;
int n; double xans, yans, xx, yy, ans = 1e18 + 7, now;
using namespace std;
struct de {
    int x, y, w;
}data[10010];
double jisuan(double x, double y)
{
    double sum = 0;
    for (int i = 1; i <= n; i++)
    {
        double dx = x - data[i].x, dy = y - data[i].y;
        sum += data[i].w * (sqrt(dx * dx + dy * dy));
    }
    return sum;
}
void tuihuo(double T)
{
    while (T > eps)
    {
        double xx = xans + (rand() * 2 - RAND_MAX) * T;
        double yy = yans + (rand() * 2 - RAND_MAX) * T;
        double now = jisuan(xx, yy);
        double del = now - ans;
        if (del < 0)//如果now比ans要优 
        {
            xans = xx;
            yans = yy;
            ans = now;	
        } 
         else if(exp(-del / T) * RAND_MAX>rand())//能否接受这个差 
    	    {
            xans = xx;
            yans = yy;
        }
        T *= t;
    }	
}
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d%d%d", &data[i].x, &data[i].y, &data[i].w);
    tuihuo(1926), tuihuo(1926), tuihuo(1926);
    printf("%.3lf %.3lf", xans, yans);
    return 0;
}		

原文地址:https://www.cnblogs.com/liuwenyao/p/10292961.html