蟻群算法(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 }

 

 

      


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM