人工智能 -- 模拟退火算法解决TSP问题(JAVA版)

计算由广州市出发走遍省内所有市的最短距离。

模拟退火算法:由两规则三函数组成。

两规则指:外层循环结束规则、内层循环结束规则。

三函数指:温度更新函数(控制温度的变化)、状态产生函数(用于产生邻结点)、状态接收函数(用于判断邻结点是否应该被接受)

本代码中退火算法介绍:

        外层循环结束规则为:温度小于某个指定的最低温度

        内层循环结束规则为:温度步长小于指定值,即每一个温度执行的状态选择次数

        状态产生函数为:bulider_neighbor(Node node),根据传入的结点,返回该结点的邻结点ArrayList集合,然后在该集合中随机选取一个结点neighbor,作为新的结点

        状态接收函数:接受条件为 neighbor的距离代价value 小于 当前结点(cur_node)的距离代价value或者根据e^-(neighbor.value-cur_node.value)/T (T指当前温度值 Temperature) 计算出一个概率值 P ,若P大于Random[0,1]之间的数,则接受,将新结点neighbor作为当前节点。若不满足上述两个条件,则拒绝接受。

        温度更新函数:此处偷懒,选择最简单的Temperature=Temperatrue*a;a的值为小于1的小数即可,保证Temperature的值下降。

package com.AI.Experiment4;

import java.util.ArrayList;
import java.util.Random;

/**
 * 模拟退火算法,解决TSP(旅行商)问题
 */

class Node {
    public int[] sol;  //存放路径
    public int value;  //存放该路径的距离代价

    public Node(int num){
        sol=new int[num];
        value=Integer.MAX_VALUE;
    }
}

public class SA {
    private int[][] Dist;   //距离矩阵
    private float Temperature;//初始温度
    private int City_num;   //城市数目
    private Node cur_node;  //初始化结点
    private Node best_neighbor; //最优邻结点
    private float a;        //降温系数

    /**
     * 传入初始化参数:
     *      1.距离矩阵
     *      2.初始温度
     * @param dist
     * @param temperature
     */
    public SA(int[][] dist, int temperature,float a) {
        Dist = dist;
        Temperature = temperature;
        this.a=a;
        City_num=dist.length;

    }

    /**
     * 将node2的内容复制到node1中
     * @param node1
     * @param node2
     */
    public void CopyNode(Node node1,Node node2){
        for(int i=0;i<City_num;i++){
            node1.sol[i]=node2.sol[i];
        }
        node1.value=node2.value;
    }

    /**
     * 模拟退火算法,主函数
     * @return
     */
    public Node SA_mian(){
        //先初始化各个参数
        init();

        Random random=new Random(); //用于生成随机数

        //外层循环退出条件,温度小于0.005
        while(Temperature>0.005){
            int step=0; //温度步长,内层循环,每一个温度执行200次计算
            while(step<1000){
                //随机获取当前结点的邻结点
                ArrayList<Node> neighbors = builder_neighbors(cur_node);//获取当前结点的邻居结点的集合
                int index= random.nextInt(neighbors.size());   //随机邻结点在集合中的下标

                Node neighbor=neighbors.get(index); //获取随机邻结点

                //判断随机邻结点的距离代价和当前结点的距离代价
                if(neighbor.value<cur_node.value){
                    //符合,则接受该邻居结点作为当前结点
                    CopyNode(cur_node,neighbor);
                    CopyNode(best_neighbor,neighbor);
                 //   System.out.println(best_neighbor.value);
                }
                else{
                    if(Math.pow(Math.E,-(neighbor.value-cur_node.value)/Temperature)>random.nextDouble()){
                        CopyNode(cur_node,neighbor);
                    }
                }

                step++;
            }

            Temperature=Temperature*a;
        }

        return best_neighbor;
    }

    /**
     * 生成传入结点的邻结点集合
     * @param node
     * @return
     */
    public ArrayList<Node> builder_neighbors(Node node){
        ArrayList<Node> neighbors=new ArrayList<>();
        Node neighbor;//临时变量存放邻居结点
        int temp;   //临时变量存放城市编号
        for(int i=1;i<City_num-1;i++){
            for (int j=2;j<City_num;j++){
                neighbor=new Node(City_num);
                
                //将当前结点复制给;邻居结点
                CopyNode(neighbor,node);
                
                //交换第i个城市和第j个城市的位置
                temp=neighbor.sol[i];
                neighbor.sol[i]=neighbor.sol[j];
                neighbor.sol[j]=temp;

                //计算邻居结点的距离代价
                neighbor.value=evaluate(neighbor);

                //将该邻居结点加入集合
                neighbors.add(neighbor);
            }
        }

        return neighbors;
    }
    
    //初始化结点
    private void init(){
        cur_node=new Node(City_num);
        best_neighbor=new Node(City_num);

        for(int i=0;i<City_num;i++){
            cur_node.sol[i]=i;
        }

        //计算初始化结点的距离代价
        cur_node.value=evaluate(cur_node);

        //将初始化结点作为最优解结点
        CopyNode(best_neighbor,cur_node);
    }

    /**
     * 计算传入结点的距离代价
     * @param node
     */
    public int evaluate(Node node){
        int distance=0;
        for(int i=1;i<City_num;i++){
            distance=distance+Dist[node.sol[i-1]][node.sol[i]];
        }

        distance=distance+Dist[node.sol[City_num-1]][node.sol[0]];

        return distance;
    }

    public static void main(String[] args) {
        int max=6555;

        String[] citys={"广州","佛山","东莞","中山","珠海","深圳","惠州","河源","汕尾","梅州","潮州","汕头","揭阳","清远","韶关","云浮","茂名","湛江","阳江","江门","肇庆"};

        int[][] Dist={
                {max ,22  ,90  ,86  ,133 ,147 ,148 ,228 ,272 ,426 ,490 ,527 ,465 ,63  ,180 ,145 ,371 ,488 ,225 ,102 ,109 },//广州到各市距离
                {22  ,max ,112 ,78  ,128 ,169 ,170 ,250 ,286 ,456 ,520 ,557 ,495 ,85  ,229 ,132 ,349 ,466 ,198 ,66  ,87  },//佛山到各市距离
                {90  ,112 ,max ,92  ,132 ,57  ,162 ,134 ,207 ,340 ,404 ,441 ,379 ,153 ,297 ,202 ,461 ,578 ,274 ,122 ,199 },//东莞到各市距离
                {86  ,78  ,92  ,max ,25  ,121 ,161 ,240 ,265 ,409 ,420 ,425 ,385 ,158 ,309 ,191 ,317 ,396 ,201 ,43  ,144 },//中山到各市距离
                {133 ,128 ,132 ,25  ,max ,162 ,195 ,282 ,307 ,452 ,462 ,467 ,427 ,202 ,354 ,230 ,328 ,407 ,199 ,87  ,193 },//珠海到各市距离
                {147 ,169 ,57  ,121 ,162 ,max ,90  ,177 ,169 ,343 ,351 ,333 ,317 ,198 ,324 ,265 ,420 ,499 ,303 ,144 ,218 },//深圳到各市距离
                {148 ,170 ,162 ,161 ,195 ,90  ,max ,87  ,130 ,259 ,284 ,289 ,249 ,188 ,271 ,278 ,452 ,531 ,335 ,180 ,231 },//惠州到各市距离
                {228 ,250 ,134 ,240 ,282 ,177 ,87  ,max ,219 ,190 ,269 ,286 ,246 ,211 ,251 ,335 ,534 ,613 ,418 ,266 ,288 },//河源到各市距离
                {272 ,286 ,207 ,265 ,307 ,169 ,130 ,219 ,max ,221 ,200 ,182 ,165 ,317 ,400 ,407 ,568 ,647 ,452 ,293 ,360 },//汕尾到各市距离
                {426 ,456 ,340 ,409 ,452 ,343 ,259 ,190 ,221 ,max ,135 ,155 ,110 ,398 ,360 ,522 ,708 ,787 ,592 ,436 ,475 },//梅州到各市距离
                {490 ,520 ,404 ,420 ,462 ,351 ,284 ,269 ,200 ,135 ,max ,49  ,29  ,421 ,439 ,545 ,718 ,797 ,601 ,446 ,498 },//潮州到各市距离
                {527 ,557 ,441 ,425 ,467 ,333 ,289 ,286 ,182 ,155 ,49  ,max ,46  ,426 ,466 ,550 ,723 ,802 ,606 ,450 ,503 },//汕头到各市距离
                {465 ,495 ,379 ,385 ,427 ,317 ,249 ,246 ,165 ,110 ,29  ,46  ,max ,387 ,413 ,511 ,684 ,763 ,567 ,412 ,464 },//揭阳到各市距离
                {63  ,85  ,153 ,158 ,202 ,198 ,188 ,211 ,317 ,398 ,421 ,426 ,387 ,max ,168 ,171 ,379 ,463 ,286 ,151 ,123 },//清远到各市距离
                {180 ,229 ,297 ,309 ,354 ,324 ,271 ,251 ,400 ,360 ,439 ,466 ,413 ,168 ,max ,323 ,531 ,615 ,436 ,301 ,293 },//韶关到各市距离
                {145 ,132 ,202 ,191 ,230 ,265 ,278 ,335 ,407 ,522 ,545 ,550 ,511 ,171 ,323 ,max ,244 ,328 ,182 ,148 ,56  },//云浮到各市距离
                {371 ,349 ,461 ,317 ,328 ,420 ,452 ,534 ,568 ,708 ,718 ,723 ,684 ,379 ,531 ,244 ,max ,96  ,130 ,275 ,267 },//茂名到各市距离
                {488 ,466 ,578 ,396 ,407 ,499 ,531 ,613 ,647 ,787 ,797 ,802 ,763 ,463 ,615 ,328 ,96  ,max ,208 ,354 ,348 },//湛江到各市距离
                {225 ,198 ,274 ,201 ,199 ,303 ,335 ,418 ,452 ,592 ,601 ,606 ,567 ,286 ,436 ,182 ,130 ,208 ,max ,158 ,201 },//阳江到各市距离
                {102 ,66  ,122 ,43  ,87  ,144 ,180 ,266 ,293 ,436 ,446 ,450 ,412 ,151 ,301 ,148 ,275 ,354 ,158 ,max ,104 },//江门到各市距离
                {109 ,87  ,199 ,144 ,193 ,218 ,231 ,288 ,360 ,475 ,498 ,503 ,464 ,123 ,293 ,56  ,267 ,348 ,201 ,104 ,max }//肇庆到各市距离
        };
        int temperature=10000;
        float a=0.98f;
        SA sa=new SA(Dist,temperature,a);
        Node node = sa.SA_mian();

        for (int i=0;i<Dist.length;i++){
            System.out.print(citys[node.sol[i]]+"\t");
        }

        System.out.println("最优解的距离代价:"+node.value);
    }
}

*注:广东省各市距离矩阵为21*21 ,数据量相对较大,若想得到最优解,需要提高初始温度或温度步长

         此解不一定正确,若要得到正确答案,可以多次运行记录下最低解。若计算机性能允许可以将初始温度和温度步长大幅度提高,保证每次都能输出最优解。(本人电脑辣鸡...)

广东省各市间距离(矩阵):

        https://blog.csdn.net/weixin_53068616/article/details/121049943?spm=1001.2014.3001.5501https://blog.csdn.net/weixin_53068616/article/details/121049943?spm=1001.2014.3001.5501https://blog.csdn.net/weixin_53068616/article/details/121049943?spm=1001.2014.3001.5501

若算法有不足或对算法有不理解的地方,欢迎评论!

  • 14
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值