启发式算法——模拟退火

启发式算法详解——模拟退火

  • 算法来源
  • 算法详解
    • 代码
    • why模拟退火能取得较好的解?
    • 模拟退火的优势

算法来源

      模拟退火算法来源于固体退火原理,是一种基于概率的算法,将固体加温至充分高,再让其徐徐冷却,冷却时粒子渐趋有序,在每个温度都达到平衡态,最后在常温时达到基态,内能减为最小。
      模拟退火算法也是不断通过随机改变数组的输入顺序来产生最优解,只不过它会以一定的概率来接受一个比当前解要差的解,因此有可能会跳出这个局部的最优解,达到全局的最优解。
      以下面的图为例,第一个版本的启发式算法由C到A后就结束了,而模拟退火则能够跳出局部解,到达E、D,最终获得最优解B。
启发式算法——模拟退火_第1张图片

算法详解

      根据热力学的原理,在温度为T时,出现能量差为dE的降温的概率为P(dE),表示为:
    P(dE) = exp( dE/(kT) )

      其中k是一个常数,exp表示自然指数,且dE<0。这条公式说白了就是:温度越高,出现一次能量差为dE的降温的概率就越大;温度越低,则出现降温的概率就越小。又由于dE总是小于0(否则就不叫退火了),因此dE/kT < 0 ,所以P(dE)的函数取值范围是(0,1) 。

      随着温度T的降低,P(dE)会逐渐降低。


代码

以一维装箱为例,代码如下:

    private void getMinBoxes(int[] bins) {
        double t = T0;
        while (t > T_END) {
            for (int i = 0; i < size; i++) {
                int[] curPermutation = getNewFire();
                int curResult = getMinimumBins(curPermutation);
                // 当前结果好于先前结果,总是接受
                if (curResult <= fit) {
                    fit = curResult;
                    bestPermutation = Arrays.copyOf(curPermutation, length);
                    permutation = Arrays.copyOf(curPermutation, length);
                } else if (Math.exp((fit - curResult) / t) > random.nextDouble()) {
                    permutation = Arrays.copyOf(curPermutation, length);
                }
            }
            t *= RATE;
        }
        return fit;
    }
    
    /**
     * 随机交换两个元素的位置
     * @author jinguo
     * @date 2021/5/13 11:30
     * @return 返回一个解集
     * */
    private int[] getNewFire() {
        int[] temp = Arrays.copyOf(permutation, length);
        int posA = random.nextInt(length);
        int posB;
        int tryCount = 0;
        do {
            posB = random.nextInt(length);
        } while (posB == posA && tryCount++ < MAX_SIZE);
        swap(temp, posA, posB);
        return temp;
    }
    
    /**
     * First-fit贪心算法
     * @author jinguo
     * @date 2021/5/13 11:30
     * @return 返回解
     * */
    public int getMinimumBins(int weights[]) {
        int result = 0;
        int boxes[] = new int[weights.length];
        for (int i = 0; i < weights.length; i++) {
            for (int j = 0; j < boxes.length; j++) {
                if (weights[i] + boxes[j] <= capacity) {
                    boxes[j] = boxes[j] + weights[i];
                    result = Math.max(result, j + 1);
                    break;
                }
            }
        }
        return result;
    }

why模拟退火能取得较好的解?

      和第一个版本的启发式算法相比,模拟退火在一定程度上接受了比当前差的解,因此有可能跳出当前的局部解集,而随着迭代次数的增加,最终结果逐渐收敛。

模拟退火的优势

      模拟退火和其他启发式算法相比真的相当简单了,效率是最高的,消耗的空间是最少的。但是模拟退火的参数设置非常重要,主要参数有:

  • T0,初始温度。初始温度如果过高,则迭代次数高,可能会增加耗时,迭代次数少,则获得最优解的概率下降。
  • T_END:结束温度。结束温度和初始温度的作用相同。
  • RATE:温度下降速率。温度下降速率越快,迭代次数越少,收敛越快,设置的过快或过慢都会影响赛算法的效率。

你可能感兴趣的:(启发式算法,启发式算法,算法)