1. 程式人生 > 實用技巧 >蟻群演算法解決TSP旅行商問題 C# (轉)

蟻群演算法解決TSP旅行商問題 C# (轉)

轉自:http://blog.sina.com.cn/s/blog_6a409d870101lwr8.html
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4  
 5 namespace ant_C
 6 {
 7     public static class Common
 8     {
 9        public static double ALPHA = 1.0; //啟發因子,資訊素的重要程度
10        public static double BETA = 2.0;   //期望因子,城市間距離的重要程度
11        public static double ROU = 0.5
; //資訊素殘留引數 12 13 public static int N_ANT_COUNT = 50; //螞蟻數量 14 public static int N_IT_COUNT = 10000; //迭代次數 15 public static int N_CITY_COUNT = 51; //城市數量 16 17 public static double DBQ = 100.0; //總的資訊素 18 public static double DB_MAX = 10e9; //一個標誌數,10的9次方 19 20 public static
double[,] g_Trial = new double[N_CITY_COUNT, N_CITY_COUNT]; //兩兩城市間資訊素,就是環境資訊素 21 public static double[,] g_Distance=new double[N_CITY_COUNT,N_CITY_COUNT]; //兩兩城市間距離 22 23 //eil51.tsp城市座標資料 24 public static double[] x_Ary=new double[] 25 { 26 37,49,52,20,40,21,17,31,52,51
, 27 42,31,5,12,36,52,27,17,13,57, 28 62,42,16,8,7,27,30,43,58,58, 29 37,38,46,61,62,63,32,45,59,5, 30 10,21,5,30,39,32,25,25,48,56, 31 30 32 }; 33 34 public static double[] y_Ary=new double[] 35 { 36 52,49,64,26,30,47,63,62,33,21, 37 41,32,25,42,16,41,23,33,13,58, 38 42,57,57,52,38,68,48,67,48,27, 39 69,46,10,33,63,69,22,35,15,6, 40 17,10,64,15,10,39,32,55,28,37, 41 40 42 }; 43 44 45 static int RAND_MAX = 0x7fff; //隨機數最大值 46 47 static Random rand = new Random(System.DateTime.Now.Millisecond); 48 49 ////返回指定範圍內的隨機整數 50 public static int rnd(int nLow, int nUpper) 51 { 52 return nLow + (nUpper - nLow) * rand.Next(RAND_MAX) / (RAND_MAX + 1); 53 } 54 55 //返回指定範圍內的隨機浮點數 56 public static double rnd(double dbLow, double dbUpper) 57 { 58 double dbTemp = (double)rand.Next(RAND_MAX) / ((double)RAND_MAX + 1.0); 59 return dbLow + dbTemp * (dbUpper - dbLow); 60 } 61 62 //返回浮點數四捨五入取整後的浮點數 63 public static double ROUND(double dbA) 64 { 65 return (double)((int)(dbA + 0.5)); 66 } 67 68 } 69 }
View Code

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Text;
  4  
  5 namespace ant_C
  6 {
  7     class CAnt
  8     {        
  9    public int[] m_nPath; //螞蟻走的路徑
 10        int[] m_nAllowedCity;//沒去過的城市
 11        
 12    int m_nCurCityNo; //當前所在城市編號
 13    int m_nMovedCityCount; //已經去過的城市數量
 14        public double m_dbPathLength; //螞蟻走過的路徑長度
 15  
 16        public CAnt()
 17        {
 18           m_nPath=new int[Common.N_CITY_COUNT];
 19           m_nAllowedCity=new int[Common.N_CITY_COUNT]; //沒去過的城市
 20        }
 21  
 22        //初始化函式,螞蟻搜尋前呼叫
 23        public void Init()
 24        {
 25  
 26            for (int i = 0; i < Common.N_CITY_COUNT; i++)
 27       {
 28       m_nAllowedCity[i]=1; //設定全部城市為沒有去過
 29       m_nPath[i]=0; //螞蟻走的路徑全部設定為0
 30       }
 31  
 32       //螞蟻走過的路徑長度設定為0
 33       m_dbPathLength=0.0; 
 34  
 35       //隨機選擇一個出發城市
 36           m_nCurCityNo = Common.rnd(0, Common.N_CITY_COUNT);
 37  
 38       //把出發城市儲存入路徑陣列中
 39       m_nPath[0]=m_nCurCityNo;
 40  
 41       //標識出發城市為已經去過了
 42       m_nAllowedCity[m_nCurCityNo]=0; 
 43  
 44       //已經去過的城市數量設定為1
 45       m_nMovedCityCount=1; 
 46  
 47        }
 48  
 49        //選擇下一個城市
 50        //返回值 為城市編號
 51        public int ChooseNextCity()
 52        {
 53       int nSelectedCity=-1; //返回結果,先暫時把其設定為-1
 54  
 55       //==============================================================================
 56       //計算當前城市和沒去過的城市之間的資訊素總和
 57       
 58       double dbTotal=0.0;
 59       double[] prob=new double[Common.N_CITY_COUNT]; //儲存各個城市被選中的概率
 60  
 61       for (int i=0;i
 62       {
 63       if (m_nAllowedCity[i] == 1) //城市沒去過
 64       {
 65                  prob[i] = System.Math.Pow(Common.g_Trial[m_nCurCityNo,i], Common.ALPHA) * System.Math.Pow(1.0 / Common.g_Distance[m_nCurCityNo,i], Common.BETA); //該城市和當前城市間的資訊素
 66       dbTotal=dbTotal+prob[i]; //累加資訊素,得到總和
 67       }
 68       else //如果城市去過了,則其被選中的概率值為0
 69       {
 70       prob[i]=0.0;
 71       }
 72       }
 73  
 74       //==============================================================================
 75       //進行輪盤選擇
 76       double dbTemp=0.0;
 77       if (dbTotal > 0.0) //總的資訊素值大於0
 78       {
 79       dbTemp=Common.rnd(0.0,dbTotal); //取一個隨機數
 80  
 81       for (int i=0;i
 82       {
 83       if (m_nAllowedCity[i] == 1) //城市沒去過
 84       {
 85       dbTemp=dbTemp-prob[i]; //這個操作相當於轉動輪盤,如果對輪盤選擇不熟悉,仔細考慮一下
 86       if (dbTemp < 0.0) //輪盤停止轉動,記下城市編號,直接跳出迴圈
 87       {
 88       nSelectedCity=i;
 89       break;
 90       }
 91       }
 92       }
 93       }
 94  
 95       //==============================================================================
 96       //如果城市間的資訊素非常小 ( 小到比double能夠表示的最小的數字還要小 )
 97       //那麼由於浮點運算的誤差原因,上面計算的概率總和可能為0
 98       //會出現經過上述操作,沒有城市被選擇出來
 99       //出現這種情況,就把第一個沒去過的城市作為返回結果
100       
101       //題外話:剛開始看的時候,下面這段程式碼困惑了我很長時間,想不通為何要有這段程式碼,後來才搞清楚。
102       if (nSelectedCity == -1)
103       {
104               for (int i = 0; i < Common.N_CITY_COUNT; i++)
105       {
106       if (m_nAllowedCity[i] == 1) //城市沒去過
107       {
108       nSelectedCity=i;
109       break;
110       }
111       }
112       }
113  
114       //==============================================================================
115       //返回結果,就是城市的編號
116       return nSelectedCity;
117        }
118  
119        //螞蟻在城市間移動
120        public void Move()
121        {
122       int nCityNo=ChooseNextCity(); //選擇下一個城市
123  
124       m_nPath[m_nMovedCityCount]=nCityNo; //儲存螞蟻走的路徑
125       m_nAllowedCity[nCityNo]=0;//把這個城市設定成已經去過了
126       m_nCurCityNo=nCityNo; //改變當前所在城市為選擇的城市
127       m_nMovedCityCount++; //已經去過的城市數量加1
128        }
129  
130        //計算螞蟻走過的路徑長度
131        public void CalPathLength()
132        {
133  
134       m_dbPathLength=0.0; //先把路徑長度置0
135       int m=0;
136       int n=0;
137  
138       for (int i=1;i
139       {
140       m=m_nPath[i];
141       n=m_nPath[i-1];
142       m_dbPathLength=m_dbPathLength+Common.g_Distance[m,n];
143       }
144  
145       //加上從最後城市返回出發城市的距離
146       n=m_nPath[0];
147           m_dbPathLength = m_dbPathLength + Common.g_Distance[m,n];
148  
149        }
150  
151  
152        //螞蟻進行搜尋一次
153        public void Search()
154        {
155       Init(); //螞蟻搜尋前,先初始化
156  
157       //如果螞蟻去過的城市數量小於城市數量,就繼續移動
158       while (m_nMovedCityCount < Common.N_CITY_COUNT)
159       {
160       Move();
161       }
162  
163       //完成搜尋後計算走過的路徑長度
164       CalPathLength();
165        }
166  
167  
168     }
169 }
View Code

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Text;
  4  
  5 namespace ant_C
  6 {
  7     class CTsp
  8     {
  9        CAnt []m_cAntAry; //螞蟻陣列
 10        public CAnt m_cBestAnt; //定義一個螞蟻變數,用來儲存搜尋過程中的最優結果
 11                              //該螞蟻不參與搜尋,只是用來儲存最優結果
 12  
 13        public CTsp()
 14        {
 15           m_cAntAry=new CAnt[Common.N_ANT_COUNT];
 16            for (int i = 0; i < Common.N_ANT_COUNT; i++)
 17            {
 18               m_cAntAry[i] = new CAnt();
 19            }
 20           m_cBestAnt=new CAnt();
 21        }
 22  
 23        //初始化資料
 24        public void InitData()
 25        {
 26  
 27           //先把最優螞蟻的路徑長度設定成一個很大的值
 28           m_cBestAnt.m_dbPathLength = Common.DB_MAX;
 29  
 30           //計算兩兩城市間距離
 31            double dbTemp = 0.0;
 32            for (int i = 0; i < Common.N_CITY_COUNT; i++)
 33            {
 34               for (int j = 0; j < Common.N_CITY_COUNT; j++)
 35               {
 36                  dbTemp = (Common.x_Ary[i] - Common.x_Ary[j]) * (Common.x_Ary[i] - Common.x_Ary[j]) + (Common.y_Ary[i] - Common.y_Ary[j]) * (Common.y_Ary[i] - Common.y_Ary[j]);
 37                  dbTemp = System.Math.Pow(dbTemp, 0.5);
 38                  Common.g_Distance[i,j] = Common.ROUND(dbTemp);
 39               }
 40            }
 41  
 42           //初始化環境資訊素,先把城市間的資訊素設定成一樣
 43           //這裡設定成1.0,設定成多少對結果影響不是太大,對演算法收斂速度有些影響
 44            for (int i = 0; i < Common.N_CITY_COUNT; i++)
 45            {
 46               for (int j = 0; j < Common.N_CITY_COUNT; j++)
 47               {
 48                  Common.g_Trial[i,j] = 1.0;
 49               }
 50            }
 51        
 52        }
 53  
 54  
 55        //更新環境資訊素
 56        public void UpdateTrial()
 57        {
 58       //臨時陣列,儲存各只螞蟻在兩兩城市間新留下的資訊素
 59            double[,] dbTempAry = new double[Common.N_CITY_COUNT, Common.N_CITY_COUNT];
 60  
 61           //先全部設定為0
 62            for (int i = 0; i < Common.N_ANT_COUNT; i++) //計算每隻螞蟻留下的資訊素
 63            {
 64               for (int j = 1; j < Common.N_CITY_COUNT; j++)
 65               {
 66                  dbTempAry[i, j] = 0.0;
 67               }
 68            }
 69  
 70  
 71       //計算新增加的資訊素,儲存到臨時數組裡
 72       int m=0;
 73       int n=0;
 74            for (int i = 0; i < Common.N_ANT_COUNT; i++) //計算每隻螞蟻留下的資訊素
 75       {
 76               for (int j = 1; j < Common.N_CITY_COUNT; j++)
 77       {
 78       m=m_cAntAry[i].m_nPath[j];
 79       n=m_cAntAry[i].m_nPath[j-1];
 80                     dbTempAry[n, m] = dbTempAry[n, m] + Common.DBQ / m_cAntAry[i].m_dbPathLength;
 81       dbTempAry[m,n]=dbTempAry[n,m];
 82       }
 83  
 84       //最後城市和開始城市之間的資訊素
 85       n=m_cAntAry[i].m_nPath[0];
 86                  dbTempAry[n, m] = dbTempAry[n, m] + Common.DBQ / m_cAntAry[i].m_dbPathLength;
 87       dbTempAry[m,n]=dbTempAry[n,m];
 88  
 89       }
 90  
 91       //==================================================================
 92       //更新環境資訊素
 93            for (int i = 0; i < Common.N_CITY_COUNT; i++)
 94       {
 95               for (int j = 0; j < Common.N_CITY_COUNT; j++)
 96       {
 97                  Common.g_Trial[i,j] = Common.g_Trial[i,j] * Common.ROU + dbTempAry[i,j];  //最新的環境資訊素 = 留存的資訊素 + 新留下的資訊素
 98       }
 99       }
100  
101        }
102  
103  
104        //開始搜尋
105        public void Search()
106        {
107  
108       //char cBuf[256]; //列印資訊用
109            string strInfo="";
110           
111            bool blFlag = false;
112  
113       //在迭代次數內進行迴圈
114       for (int i=0;i
115       {
116               blFlag = false;
117  
118       //每隻螞蟻搜尋一遍
119               for (int j = 0; j < Common.N_ANT_COUNT; j++)
120       {
121       m_cAntAry[j].Search(); 
122       }
123  
124       //儲存最佳結果
125               for (int j = 0; j < Common.N_ANT_COUNT; j++)
126       {
127       if (m_cAntAry[j].m_dbPathLength < m_cBestAnt.m_dbPathLength)
128       {       
129                     m_cBestAnt.m_dbPathLength=m_cAntAry[j].m_dbPathLength;
130                     m_cBestAnt.m_nPath = m_cAntAry[j].m_nPath;
131  
132                      blFlag = true;
133  
134                  }
135       }
136  
137       //更新環境資訊素
138       UpdateTrial();
139  
140       //輸出目前為止找到的最優路徑的長度
141               if (blFlag == true)
142               {
143                  strInfo = String.Format("[{0}] {1}", i + 1, m_cBestAnt.m_dbPathLength);
144                  Console.WriteLine(strInfo);
145               }
146  
147  
148       }
149  
150        }
151  
152  
153  
154     }
155 }
View Code
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4  
 5  
 6  
 7 namespace ant_C
 8 {
 9  
10     class AO
11     {
12        static void Main(string[] args)
13        {
14            CTsp tsp=new CTsp();
15           tsp.InitData();
16           tsp.Search();
17  
18            string strInfo="";
19  
20            strInfo = String.Format("best path length = {0} ", tsp.m_cBestAnt.m_dbPathLength);
21           Console.WriteLine(strInfo);
22  
23            for (int i = 0; i < Common.N_CITY_COUNT; i++)
24            {
25               strInfo = String.Format("{0} ", tsp.m_cBestAnt.m_nPath[i] + 1);
26               Console.Write(strInfo);
27            }
28  
29           Console.Read();
30  
31        }
32     }
33 }