zoukankan      html  css  js  c++  java
  • 蚁群算法(Java)tsp问题

     

    1理论概述

    1.1TSP问题

        旅行商问题,即TSP问题(旅行推销员问题、货郎担问题),是数学领域中著名问题之一。假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。TSP问题是一个组合优化问题。该问题可以被证明具有NP计算复杂性,迄今为止,这类问题中没有一个找到有效解决算法,因此我们经常用一些近似求解算法,遗传算法、蚁群算法、粒子群算法等等。

    1.2、蚁群算法

    蚁群算法是一种仿生学算法,是由自然界中蚂蚁觅食的行为而启发的。在自然界中,蚂蚁觅食过程中,蚁群总能够按照寻找到一条从蚁巢和食物源的最优路径。以下是蚁群觅食过程:


    在图
    1a)中,一群蚂蚁从AE觅食,由于是直线路径,所以蚂蚁直接从源到目的地。在AE之间多了一个障碍物(b)图,那么在H点或者C点的蚂蚁将要做选择,由于一开始路上没有前面蚂蚁留下的信息素,蚂蚁朝着两个方向行进的概率是相等的。但是当有蚂蚁走过时,它将会在它行进的路上释放出信息素,并且这种信息素会以一定的速率散发掉。它后面的蚂蚁通过路上信息素的浓度,做出决策,往左还是往右。很明显,沿着短边的的路径上信息素将会越来越浓,随着时间的增长,右边路径的信息素浓度会因为路径的长度而散发掉,所以会有越来越多的蚂蚁沿着较短的路径前行。如图c                                  

    蚁群算法的缺点是收敛速度慢,容易陷入局部最优解。

    2、算法流程

    假设蚁群中所有蚂蚁的数量为m,所有城市之间的信息素用矩阵pheromone表示,最短路径为bestLength,最佳路径为bestTour。每只蚂蚁都有自己的内存,内存中用一个禁忌表(Tabu)来存储该蚂蚁已经访问过的城市,表示其在以后的搜索中将不能访问这些城市;还有用另外一个允许访问的城市表(Allowed)来存储它还可以访问的城市;另外还用一个矩阵(Delta)来存储它在一个循环(或者迭代)中给所经过的路径释放的信息素;还有另外一些数据,例如一些控制参数(αβρQ)用于辅助计算信息素挥发、下一个城市选中概率等等,该蚂蚁行走完全程的总成本或距离(tourLength)等。假定算法总共运行maxgen次,运行时间为t。图三是算法流程图。(注:实验系数的选定是多次试验计算的结果见论文table1

    2.1、每只蚂蚁行进过程

    为每只蚂蚁选择下一个节点,该节点只能从未选择节点中以某种概率搜索到,首先计算城市选中概率,之后以一定的原则计算下一步要选的城市,如果该城市没去过,则下一个城市就是该城市。本实验的选择方式是,产生一个随机数,顺序计算各个城市的选中概率之和,直到大于该随机数,则选择循环系数代表的城市(前提是该城市没选过。)遍历完所有节点后,将起始节点加入到 tour中,形成一个完整回路。保留回路长度 tourlength。接下来计算每个蚂蚁的信息素矩阵值。最后计算最佳路径,比较每个蚂蚁的路径成本,然后和bestLength比较,若它的路径成本比bestLength小,则将该值赋予bestLength,并在本次迭代中输出最优路径。本次迭代每只蚂蚁走完后结束。只要没有到达指定的迭代次数,则蚂蚁重新随机重置起始点,进入下一次迭代。

    2.2、实验终止

    如果达到最大迭代次数maxgen,算法终止,输出最优路径和最优路径长度;否则,重新初始化所有的蚂蚁的信息,并且重新选择起始位置为每只蚂蚁。根据几次的实验结果表明,在迭代次数较大的时候(>1000)基本在250次迭代以内就能达到收敛路径长,即达到局部最优。由于每次试验的结果不同,也表明蚁群算法容易陷入局部最优,而非每次都可以得到全局最优,当然,迭代次数少,可能最优的路径长还未得到就已经迭代结束。由于没有与其他算法作比较,对于蚁群算法收敛速度慢这个缺陷无法比较。

    (2)

    路径误差:

     

     

    图三

    2.3、数据来源

    本次试验数据来源于TSPLib,http://comopt.ifi.uni-heidelberg.de/software/TSPLIB95/。为方便实验,数据只要包含城市总数,城市编号,城市横纵坐标即可。

    图四为算法数据流程图:

     

     

    图四

     

    论文中的算法描述:

     

     

    3、算法实现描述

    工程主要包括:蚂蚁类、蚁群算法、主调程序。

    3.1、蚂蚁类主要包括以下几点:

    顺序参观城市记录 int[]tour,城市是否参观记录int[] unvisitedcity,蚂蚁所走的总路长int tourlength,城市数目;方法主要有随机城市选择函数 void RandomSelectCity(int citycount),下一个城市选择函数 void SelectNextCity(int index,double[][]tao,int[][]distance)和总路程长度计算函数 void CalTourLength(int [][]distance)

    3.2、蚁群算法主要包括以下几点:

    数据成员:

    ant []ants; //定义蚂蚁群

    int antcount;//蚂蚁的数量

    int [][]distance;//表示城市间距离

    double [][]tao;//信息素矩阵

    int citycount;//城市数量

    int[]besttour;//求解的最佳路径

    int bestlength;//求的最优解的长度

    方法成员:

    初始化函数,初始化文件信息,信息素矩阵,上述变量,蚂蚁初始位置等信息void init(String filename,int antnum)

    蚁群算法主要运行程序,包括迭代次数为实验参数,记录每一只蚂蚁的行进过程,计算本次迭代的这群蚂蚁的最优路径长,如果出现更短的路径,更新路径记录变量,迭代一次之后更新信息素矩阵以及蚂蚁重新初始化最初位置,知道到达指定迭代次数,输出收敛路径长。经过几次试验表明,一般在100次内可以达到一个收敛值,后续的若干次的剩余的迭代次数输出的路径长基本不变了。但是必须要到指定的迭代次数才会停止实验。

    3.3、主程序包括以下几点:

    调用蚁群算法,给定蚂蚁数量,城市信息文件,迭代次数,最后输出最优(局部)路径结果。蚁群算法内部,在对蚂蚁行进记录时会调用蚂蚁类的城市选择函数。

    3.4、类关系图:

     

      1 import java.io.*;
      2 /**
      3  *蚁群优化算法,用来求解TSP问题
      4  */
      5 public class ACO {
      6    
      7     ant []ants; //定义蚂蚁群
      8     int antcount;//蚂蚁的数量
      9     int [][]distance;//表示城市间距离
     10     double [][]tao;//信息素矩阵
     11     int citycount;//城市数量
     12     int[]besttour;//求解的最佳路径
     13     int bestlength;//求的最优解的长度
     14     //filename tsp数据文件
     15     //antnum 系统用到蚂蚁的数量
     16     public void init(String filename,int antnum) throws FileNotFoundException, IOException{
     17         antcount=antnum;
     18         ants=new ant[antcount];
     19         //读取数据tsp里的数据包括第I个城市与城市的X,Y坐标
     20         int[] x;
     21         int[] y;
     22         String strbuff;
     23         BufferedReader tspdata = new BufferedReader(new InputStreamReader(new FileInputStream(filename)));
     24         strbuff = tspdata.readLine();//读取第一行,城市总数(按文件格式读取)
     25         citycount = Integer.valueOf(strbuff);
     26         distance = new int[citycount][citycount];
     27         x = new int[citycount];
     28         y = new int[citycount];
     29         for (int citys = 0; citys < citycount; citys++) {
     30             strbuff = tspdata.readLine();
     31             String[] strcol = strbuff.split(" ");
     32             x[citys] = Integer.valueOf(strcol[1]);//读取每排数据的第2二个数字即横坐标
     33             y[citys] = Integer.valueOf(strcol[2]);
     34         }
     35         //计算两个城市之间的距离矩阵,并更新距离矩阵
     36         for (int city1 = 0; city1 < citycount - 1; city1++) {
     37             distance[city1][city1] = 0;
     38             for (int city2 = city1 + 1; city2 < citycount; city2++) {
     39                 distance[city1][city2] = (int) (Math.sqrt((x[city1] - x[city2]) * (x[city1] - x[city2])
     40                         + (y[city1] - y[city2]) * (y[city1] - y[city2])));
     41                 distance[city2][city1] = distance[city1][city2];//距离矩阵是对称矩阵
     42             }
     43         }
     44         distance[citycount - 1][citycount - 1] = 0;
     45         //初始化信息素矩阵
     46         tao=new double[citycount][citycount];
     47         for(int i=0;i<citycount;i++)
     48         {
     49             for(int j=0;j<citycount;j++){
     50                 tao[i][j]=0.1;
     51             }
     52         }
     53         bestlength=Integer.MAX_VALUE;
     54         besttour=new int[citycount+1];
     55         //随机放置蚂蚁
     56         for(int i=0;i<antcount;i++){
     57             ants[i]=new ant();
     58             ants[i].RandomSelectCity(citycount);
     59         }
     60     }
     61     //maxgen ACO的最多循环次数
     62     public void run(int maxgen){
     63         for(int runtimes=0;runtimes<maxgen;runtimes++){
     64             //每次迭代,所有蚂蚁都要跟新一遍,走一遍
     65             //System.out.print("no>>>"+runtimes);
     66             //每一只蚂蚁移动的过程
     67             for(int i=0;i<antcount;i++){
     68                 for(int j=1;j<citycount;j++){
     69                     ants[i].SelectNextCity(j,tao,distance);//每只蚂蚁的城市规划
     70                 }
     71                 //计算蚂蚁获得的路径长度
     72                 ants[i].CalTourLength(distance);
     73                 if(ants[i].tourlength<bestlength){
     74                     //保留最优路径
     75                     bestlength=ants[i].tourlength;
     76                     //runtimes仅代表最大循环次数,但是只有当,有新的最优路径的时候才会显示下列语句。
     77                     //如果后续没有更优解(收敛),则最后直接输出。
     78                     System.out.println("第"+runtimes+"代(次迭代),发现新的最优路径长度:"+bestlength);
     79                     for(int j=0;j<citycount+1;j++)
     80                         besttour[j]=ants[i].tour[j];//更新路径
     81                 }
     82             }
     83             //更新信息素矩阵
     84             UpdateTao();
     85             //重新随机设置蚂蚁
     86             for(int i=0;i<antcount;i++){
     87                 ants[i].RandomSelectCity(citycount);
     88             }
     89         }
     90        }
     91     /**
     92      * 更新信息素矩阵
     93      */
     94     private void UpdateTao(){
     95         double rou=0.5;
     96         //信息素挥发
     97         for(int i=0;i<citycount;i++)
     98             for(int j=0;j<citycount;j++)
     99                 tao[i][j]=tao[i][j]*(1-rou);
    100         //信息素更新
    101         for(int i=0;i<antcount;i++){
    102             for(int j=0;j<citycount;j++){
    103                 tao[ants[i].tour[j]][ants[i].tour[j+1]]+=1.0/ants[i].tourlength;
    104             }
    105         }
    106     }
    107     /* 输出程序运行结果
    108      */
    109     public void ReportResult(){
    110         System.out.println("最优路径长度是"+bestlength);
    111         System.out.println("蚁群算法最优路径输出:"); 
    112         for(int j=0;j<citycount+1;j++)
    113             System.out.print( besttour[j]+">>");//输出最优路径
    114     }
    115 }
     1 import java.util.Random;
     2 /*
     3  蚂蚁类
     4  */
     5 public class ant {
     6     /**
     7      * 蚂蚁获得的路径
     8      */
     9     public int[]tour;//参观城市顺序
    10     //unvisitedcity 取值是0或1,1表示没有访问过,0表示访问过
    11     int[] unvisitedcity;
    12     /**
    13      * 蚂蚁获得的路径长度
    14      */
    15     public int tourlength;//某蚂蚁所走路程总长度。
    16     int citys;//城市个数
    17 /**
    18  * 随机分配蚂蚁到某个城市中
    19  * 同时完成蚂蚁包含字段的初始化工作
    20  * @param citycount 总的城市数量
    21  */
    22     public void RandomSelectCity(int citycount){
    23         citys=citycount;
    24         unvisitedcity=new int[citycount];
    25         tour=new int[citycount+1];
    26         tourlength=0;
    27         for(int i=0;i<citycount;i++){
    28             tour[i]=-1;
    29             unvisitedcity[i]=1;
    30         }//初始化各个变量
    31         
    32         long r1 = System.currentTimeMillis();//获取当前时间
    33         Random rnd=new Random(r1);
    34         int firstcity=rnd.nextInt(citycount);//随机指定第一个城市
    35         unvisitedcity[firstcity]=0;//0表示访问过
    36         tour[0]=firstcity;//起始城市
    37     }
    38     /**
    39      * 选择下一个城市
    40      * @param index 需要选择第index个城市了
    41      * @param tao   全局的信息素信息
    42      * @param distance  全局的距离矩阵信息
    43      */
    44     public void SelectNextCity(int index,double[][]tao,int[][]distance){
    45         double []p;
    46         p=new double[citys];//下一步要走的城市的选中概率
    47         //计算选中概率所需系数。
    48         double alpha=1.0;
    49         double beta=2.0;
    50         double sum=0;
    51         int currentcity=tour[index-1];//蚂蚁所处当前城市
    52         //计算公式中的分母部分(为下一步计算选中概率使用)
    53         for(int i=0;i<citys;i++){
    54             if(unvisitedcity[i]==1)//没走过
    55                 sum+=(Math.pow(tao[currentcity][i], alpha)*
    56                         Math.pow(1.0/distance[currentcity][i], beta));
    57         }
    58         //计算每个城市被选中的概率
    59         for(int i=0;i<citys;i++){
    60             if(unvisitedcity[i]==0)
    61                 p[i]=0.0;//城市走过了,选中概率就是0
    62             else{
    63                 //没走过,下一步要走这个城市的概率是?
    64                 p[i]=(Math.pow(tao[currentcity][i], alpha)*
    65                         Math.pow(1.0/distance[currentcity][i], beta))/sum;
    66             }
    67         }
    68         long r1 = System.currentTimeMillis();
    69         Random rnd=new Random(r1);
    70         double selectp=rnd.nextDouble();
    71         //轮盘赌选择一个城市;
    72         double sumselect=0;
    73         int selectcity=-1;
    74         //城市选择随机,直到n个概率加起来大于随机数,则选择该城市
    75         for(int i=0;i<citys;i++){//每次都是顺序走。。。。。
    76             sumselect+=p[i];
    77             if(sumselect>=selectp){
    78                 selectcity=i;
    79                 break;
    80             }
    81         }
    82         if (selectcity==-1)//这个城市没有走过
    83             System.out.println();
    84         tour[index]=selectcity;
    85         unvisitedcity[selectcity]=0;
    86     }
    87     /**
    88      * 计算蚂蚁获得的路径的长度
    89      * @param distance  全局的距离矩阵信息
    90      */
    91     public void CalTourLength(int [][]distance){
    92         tourlength=0;
    93         tour[citys]=tour[0];//第一个城市等于最后一个要到达的城市
    94         for(int i=0;i<citys;i++){
    95             tourlength+=distance[tour[i]][tour[i+1]];//从A经过每个城市仅一次,最后回到A的总长度。
    96         }    
    97     }
    98 }
     1 import java.io.FileNotFoundException;
     2 import java.io.IOException;
     3 import java.util.logging.Level;
     4 import java.util.logging.Logger;
     5 //蚁群算法求解旅行商问题,TSP数据来源
     6 //http://comopt.ifi.uni-heidelberg.de/software/TSPLIB95/
     7 //数据中包括城市总量,每个城市的横纵坐标
     8 public class Main {
     9     /**
    10      * @param args the command line arguments
    11      */
    12     public static void main(String[] args) {
    13         ACO aco;
    14         aco=new ACO();
    15         try {
    16             aco.init("att48.txt", 100);//城市信息文件,蚂蚁数量
    17             aco.run(1000);//迭代次数
    18             aco.ReportResult();
    19         } catch (FileNotFoundException ex) {
    20             Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    21         } catch (IOException ex) {
    22             Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    23         }
    24     }
    25 }

     

          

  • 相关阅读:
    poj 3074(DLX)
    zoj 3209(DLX)
    hdu 4531(模拟+BFS+DFS)
    hdu 2065(递推+矩阵优化)
    poj 3714 (最近点对)
    zoj 3690(递推+矩阵优化)
    poj 3076(DLX)
    hdu 4533(一种很巧妙的方法|线段树+扫描线)
    hdu 4513(模拟)
    sql server 2008 评估已过期。
  • 原文地址:https://www.cnblogs.com/8335IT/p/5635892.html
Copyright © 2011-2022 走看看