蟻群演算法解決TSP旅行商問題 C# (轉)
阿新 • • 發佈:2020-11-03
轉自: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.5View Code; //資訊素殘留引數 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 staticdouble[,] 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 }
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 }