蚁群算法求解TSP问题

package ZhiXinGeGe.ServiceImpl;


import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class TSP {
    public static final int m=100;          //蚂蚁总量
    public static final int n=31;           //城市总数
    public static final int NC_max=100;     //最大迭代次数
    public static final double Alpha=1;     //象征信息素重要程度的参数
    public static final double Beta=5;      //象征启发式因子重要程度的参数
    public static final double Rho=0.1;     //信息素蒸发系数
    public static final double Q=100;       //信息素增加强度系数(另一种翻译为信息素总量)
    public static final double C[][]        //城市经纬度存储
            =new double[][]{
            { 1304, 2312 },
            { 3639, 1315 },
            { 4177, 2244 },
            { 3712, 1399 },
            { 3488, 1535 },
            { 3326, 1556 },
            { 3238, 1229 },
            { 4196, 1004 },
            { 4312, 790 },
            { 4386, 570 },
            { 3007, 1970 },
            { 2562, 1756 },
            { 2788, 1491 },
            { 2381, 1676 },
            { 1332, 695 },
            { 3715, 1678 },
            { 3918, 2179 },
            { 4061, 2370 },
            { 3780, 2212 },
            { 3676, 2578 },
            { 4029, 2838 },
            { 4263, 2931 },
            { 3429, 1908 },
            { 3507, 2367 },
            { 3394, 2643 },
            { 3439, 3201 },
            { 2935, 3240 },
            { 3140, 3550 },
            { 2545, 2357 },
            { 2778, 2826 },
            { 2370, 2975 }
        };

    static double D[][]=new double[n][n];          //表示完全图的邻接矩阵
    static double Eta[][]=new double[n][n];        //表示启发式因子,为D中的距离的倒数
    static double DeltaTau[][]=new double[n][n];   //表示启发式因子的变化量
    static double Tau[][]=new double[n][n];        //路径上面信息素的浓度
    static int Tabu[][]=new int[m][n];             //禁忌表,存储走过的路径,一维存第几只蚂蚁,二维存该蚂蚁已经走过的路

    static double L_best[]=new double[NC_max];     //存储每次迭代的路径的最短长度
    static double L_ave[]=new double[NC_max];      //存储每次迭代的路径的平均长度
    static int R_best[][]=new int[NC_max][n];      //存储每次迭代的最佳路线

    public static void ValueInit(){                       //初始化各个参数
        for (int i=0;i<n;i++){              //初始化D:表示完全图的邻接矩阵
            for (int j=0;j<n;j++){
                if (i!=j)
                    D[i][j]=Math.pow(Math.pow((C[i][0]-C[j][0]),2)+Math.pow((C[i][1]-C[j][1]),2),0.5);//勾股定理
                else
                    D[i][j]=0.000000000000000000001;//应该为0,但后面要取倒数
            }
        }

        for (int i=0;i<n;i++)               //初始化Eta:表示启发式因子,为D中距离的倒数
            for (int j=0;j<n;j++)
                Eta[i][j]=1.0/D[i][j];

        for (int i=0;i<n;i++)               //初始化DeltaTau:表示启发式因子的变化量
            for (int j=0;j<n;j++)
                DeltaTau[i][j]=0;

        for (int i=0;i<n;i++)               //初始化Tau:表示路径上的信息素浓度
            for (int j=0;j<n;j++)
                Tau[i][j]=1.0;

        for (int i=0;i<m;i++)               //初始化Tabu:禁忌表
            for (int j=0;j<n;j++)
                Tabu[i][j]=0;
    }
    /**
    void ValueDisplayTabu(int p[][]){       //禁忌表显示函数
        for (int i=0;i<m;i++)
            for (int j=0;j<n;j++)
                System.out.println();
    }
    */

    /**
     void ValueDisplayTau(int p[][]){       //信息素浓度显示函数
     for (int i=0;i<m;i++)
     for (int j=0;j<n;j++)
     System.out.println();
     }
     */

    public static double rnd(double lower,double uper){                   //生成lower和uper之间的一个double类型的随机数
        int max=100,min=1;
        long randomNum = System.currentTimeMillis();        //方法返回从1970年1月1日0时0分0秒(这与UNIX系统有关)到现在的一个long型的毫秒数,取模之后即可得到所需范围内的随机数。
        int ran = (int) (randomNum%(max-min)+min);
        return (ran/(double)max)*(uper-lower)+lower;
    }
    public static void main(String[] args){
        ValueInit();                                        //第一步:进行变量的初始化
        int NC=0;                                           //初始化迭代次数、
        while (NC<NC_max){
            List<Integer> temp=new ArrayList<>();            //第二步:将m只蚂蚁随机的放在n个城市上
            for (int i=0;i<Math.ceil((double)m/(double)n);i++)
                for (int j=0;j<n;j++)
                    temp.add(j);                            //从后部插入

            Collections.shuffle(temp);                      //打乱list里的元素次序

            for (int i=0;i<m;i++)
                Tabu[i][0]=temp.get(i);                     //禁忌表,记录每只蚂蚁出生城市

            for(int j=1;j<n;j++){                           //因为出生在一个城市,所以j从1开始到n
                for (int i=0;i<m;i++){
                    List<Integer> visited=new ArrayList<>();//第i只蚂蚁已访问过的城市
                    List<Integer> J=new ArrayList<>();      //第i只蚂蚁待访问的城市
                    List<Double> P=new ArrayList<>();       //第i只蚂蚁带访问的城市的概率

                    double Psum=0.0;                        //概率值和
                    double rate=0.0;                        //随机数
                    double choose=0.0;                      //轮盘赌算法累加值
                    int to_visit;                           //下一个要去的城市

                    for (int k=0;k<j;k++)
                        visited.add(Tabu[i][k]);            //初始化visited

                    for (int k=0;k<n;k++){
                        if (visited.indexOf(k)==-1){        //在visited里查找k有没有被访问,若没有返回-1
                            J.add(k);                       //J初始化
                            P.add(0.0);                     //P初始化
                        }
                    }

                    for (int k=0;k<P.size();k++){           //计算去下一个城市的概率
                        P.set(k,Math.pow(Tau[visited.get(visited.size()-1)][J.get(k)],Alpha)*Math.pow(Eta[visited.get(visited.size()-1)][J.get(k)],Beta));
                        Psum+=P.get(k);
                    }

                    rate=rnd(0.0,Psum);               //使用轮盘赌算法,挑选下一个要去的城市

                    to_visit=-1;                            //解除java报警
                    for (int k=0;k<P.size();k++){
                        choose+=P.get(k);
                        if (choose>rate){
                            to_visit=J.get(k);
                            break;
                        }
                    }
                    if (to_visit==-1)
                        System.out.println("to_visit未被赋值");
                    else
                        Tabu[i][j]=to_visit;                 //更新禁忌表
                }
            }

            //第四步:记录本次迭代蚂蚁行走的路线数据
            double L[]=new double[m];                        //记录本代每只蚂蚁走的路程,并初始化
            for (int i=0;i<n;i++){
                L[i]=0.0;
            }
            for (int i=0;i<m;i++){
                for (int j=0;j<n-1;j++){
                    L[i]+=D[Tabu[i][j]][Tabu[i][j+1]];
                }
                L[i]+=D[Tabu[i][0]][Tabu[i][n-1]];          //最后终点到起点
            }
            double min_value=L[0];                          //声明本代所有蚂蚁行走距离最小值的临时变量
            double sum_value=L[0];                          //声明本代所有蚂蚁行走距离总值的临时变量
            int min_index=0;                                //记录本代所有蚂蚁行走距离最小值的下标
            for (int i=1;i<m;i++){
                sum_value+=L[i];
                if (L[i]<min_value){
                    min_value=L[i];
                    min_index=i;
                }
            }
            L_best[NC]=min_value;                           //每代路径的最短长度
            L_ave[NC]=sum_value/m;                          //每代路径的平均长度

            for (int i=0;i<n;i++){
                R_best[NC][i]=Tabu[min_index][i];           //记录每代最短的路径数据
            }

            System.out.println(NC+":L_best is "+L_best[NC]+"  L_ave is "+L_ave[NC]);

            NC++;                                           //迭代继续

            //第五步:更新信息素
            for (int i=0;i<m;i++){
                for (int j=0;j<n-1;j++){
                    DeltaTau[Tabu[i][j]][Tabu[i][j+1]]+=Q/L[i];//此次循环在整个路径上的信息素增量
                }
                DeltaTau[Tabu[i][n-1]][Tabu[i][0]]+=Q/L[i];
            }

            for (int i=0;i<n;i++){
                for (int j=0;j<n;j++){
                    Tau[i][j]=(1-Rho)*Tau[i][j]+DeltaTau[i][j];//考虑信息素挥发,更新后的信息素
                }
            }

            for (int i=0;i<m;i++)                              //禁忌表清空
                for (int j=0;j<n;j++)
                    Tabu[i][j]=0;

        }

        //第六步:输出结果
        double min_L=L_best[0];
        int min_L_index=0;
        int Shortest_Route[]=new int[n];

        for (int i=0;i<NC;i++){
            if (L_best[i]<min_L){
                min_L=L_best[i];
                min_L_index=i;
            }
        }
        System.out.println( "The length of the shortest route is " + min_L );
        System.out.println("The number of iteration is " + min_L_index);
        System.out.println("The Shortest route is: ");
        System.out.print("start");
        for (int i=0;i<n;i++){
            Shortest_Route[i]=R_best[min_L_index][i];
            System.out.print("->"+Shortest_Route[i]);
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值