元启发式方法之模拟退火算法

来源:互联网 发布:澳大利亚外卖软件 编辑:程序博客网 时间:2024/05/17 17:17

模拟退火也叫做蒙特卡罗退火、统计冷却、概率爬山、随机松弛和概率交换算法,它来自于对热力学过程的模拟。为了生成规则晶体,先将原材料加热到熔化状态,再将晶体熔融液徐徐降温,使之凝固成晶体结构。在冷却过程中,如果降温太快,则会带来一些不良后果,特别是导致所形成的晶体不够规则,并且能量远远高于一个完美结构的晶体。物理系统和优化问题之间有明显的相似点,例如,物理系统中的能量就相当于优化问题的评估函数;快速淬火就相当于局部搜索;徐徐退火就相当于模拟退火的过程;温度就相当于模拟退火的控制参数T(后面有详细内容)等等。

在搜索过程中如果过早结束,就会陷入局部最优的情况,为了跳出局部最优,引入一个接受概率P和参数T。在当前解的邻域内选择一点,如果比当前解好,则总是接受它;如果没有当前解好则以接受概率接受它。注意,接受概率中的T是随着时间从大到小变化的(冷却温度),一开始T值很大,近似于随机搜索(随机选择当前解);后来T很小,近似于普通搜索法(选择最优作为当前解)。其中接受概率的定义为:

 

这是针对极大化问题的,如果是极小化问题则只需将指数的分子的两个变量交换位置。

由公式可以看出,当T很大时,则两个点的质量竞争的重要性就很小,对结果影响不大,这是概率接近于0.5,等同于随机选取;当T很小(T=1)时,概率接近于1,这就退化为普通局部搜索法了(每次都选择较优解作为当前解)。因此,T的值选择依据问题而定,既不能太大,也不能太小。另外,当T值固定时,如果新解与当前解质量相当,那么p为0.5;如果新解好于当前解,那么p大于0.5,而且新解越好,接受的概率就越大。这些事实都是符合常理的。      

下面以TSP问题为例,给出模拟退火算法的一种实现(java实现):

import java.util.ArrayList;import java.util.Random;import tools.TSPData;import interfaces.IRunning;/* * 使用模拟退火方法求解TSP问题 */public class SASolver implements IRunning{//当前解private ArrayList<Integer> current;//邻域内下一个解private ArrayList<Integer> next;//城市数量private int number;//开始的城市标号private int origin;//城市信息文件名private String file;//近似最优解private double shortestDist;//距离矩阵private double[][] distances;    public SASolver(String filename){file = filename;shortestDist = 0;current = new ArrayList<Integer>();next = new ArrayList<Integer>();}@Overridepublic void run() {//搜索迭代次数int iteration = number * 2;//退火温度        double T = 10000.0;        //退火速率        double cRate = 0.9999;        //凝固温度        double ST = 0.00001;        //随机数发生器        Random rand = new Random(System.nanoTime());                initialSolution();                double dist = getTotalDist(current);        shortestDist = dist;        origin = 0;        while(T > ST){int count = iteration;double nextDist;dist = shortestDist;while(count > 0){getNextSolution();nextDist = getTotalDist(next);if (nextDist < dist) {current = (ArrayList<Integer>) next.clone();shortestDist = nextDist;} else {double r = rand.nextDouble();if (r < Math.exp((dist - nextDist) / T)) {current = (ArrayList<Integer>) next.clone();shortestDist = nextDist;}}count--;}T *= cRate;}        //shortestDist = dist;        System.out.println("算法结束");}    /*     * 总是根据当前解生成邻域新解     */private void getNextSolution() {next = (ArrayList<Integer>)current.clone();Random rand = new Random(System.nanoTime());//这里的算子:随机交换两个城市的位置(0作为起始点除外)int index1 = rand.nextInt(number - 1) + 1;int index2 = index1;while(index2 == index1)index2 = rand.nextInt(number - 1) + 1;int temp = next.get(index1);next.set(index1, next.get(index2));next.set(index2, temp);}private void initialSolution() {int i;for(i = 0; i < number; i++){if(i != origin)    current.add(i);}current.add(0, origin);}private double getTotalDist(ArrayList<Integer> list) {double res = 0;int i = 0;for(; i < number - 1; i++)res += distances[list.get(i)][list.get(i + 1)];if(number > 1)res += distances[list.get(number - 1)][0];return res;}@Overridepublic void init() {distances = TSPData.getDistances(file);number = distances[0].length;}@Overridepublic void print() {System.out.println("算法得到的近似最优解为:" + shortestDist);System.out.println("该解对应的路径为:");int i;for(i = 0; i < number; i++)System.out.print(current.get(i) + "-->");System.out.println(current.get(0));}}

   这里使用的算子是随机交换两个城市的位置。 实验得到的解(18左右)与最优解(14)很相近。 (待修订)