码迷,mamicode.com
首页 > 编程语言 > 详细

遗传算法解决旅行商问题GA_TSP

时间:2014-12-04 13:56:57      阅读:691      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   io   ar   color   os   使用   sp   

心血来潮把GA_TSP问题用C++封装起来搞了一遍,期间真是收益不小。

主要是用STL中的vector和list,结构体赋值中遇到了一些难点,原谅我自己是一棵白菜。

 

选择方法:用种群前面最优的20%代替后面的20%进行淘汰(当然这个比例可以自己拟定,修改代码中得pm_即可)。

变异方法:交换一个路径上随机产生的两个城市。

交叉方法:三交换启发交叉(THGA)。

 

genticTsp.h 代码如下:

bubuko.com,布布扣
 1 #ifndef GENTIC_TSP_H_
 2 #define GENTIC_TSP_H_
 3 #include <iostream>
 4 #include <vector>
 5 #include <string>
 6 #define CITIES 99
 7 #define UNITS 50
 8 #define MAX_GEN 15
 9 
10 
11 struct city{
12     int id;
13     int x;
14     int y;
15 };
16 
17 struct unit{
18     double length;
19     std::vector<int> path;
20     bool operator<(const struct unit &other) const
21     {
22         return length < other.length;
23     }
24 };
25 
26 
27 class GenticTSP{
28     public:
29         GenticTSP();
30         void initMatrix(const std::string &filename);//file to matrix
31         void initGroup();//shuffle a group
32         double lenOfUnit(unit &p);//
33         int searchCity(unit &, int id);//search a city‘s id for cross
34         void selectGroup();
35         void crossUnits(unit &p, unit &q, unit &r);
36         void mutateGroup();
37         void evoluteGroup();
38         void printBestUnit();
39         ~GenticTSP();
40     private:
41         unit bestUnit_;
42         double pm_;// mutate probability
43         double ps_;//save probability
44 
45 };
46 
47 #endif  /*GENTIC_TSP_H_*/
GenticTsp.h

genticTsp.cpp代码如下:

bubuko.com,布布扣
  1 #include "GenticTSP.h"
  2 #include <iostream>
  3 #include <fstream>
  4 #include <string>
  5 #include <vector>
  6 #include <list>
  7 #include <algorithm>
  8 #include <math.h>
  9 #include <time.h>
 10 #include <string.h>
 11 
 12 using namespace std;
 13 
 14 city cities[CITIES];
 15 unit group[UNITS];
 16 double cityMatrix[CITIES][CITIES];
 17 
 18 GenticTSP::GenticTSP()
 19     :pm_(0.2), ps_(0.8)
 20 {
 21 
 22 }
 23 
 24 GenticTSP::~GenticTSP()
 25 {
 26 
 27 }
 28 
 29 void GenticTSP::initMatrix(const string &filename)
 30 {
 31     int i, j;
 32     ifstream in(filename);
 33     for(i = 0; i < CITIES; ++i)
 34     {
 35 
 36         in >> cities[i].id >> cities[i].x >> cities[i].y;
 37     }
 38 
 39     for(i = 0; i < CITIES; ++i)
 40     {
 41         cityMatrix[i][i] = 0;
 42         for(j = i + 1; j < CITIES; ++j)
 43         {
 44             cityMatrix[i][j] = sqrt((cities[i].x - cities[j].x) * (cities[i].x - cities[j].x) + (cities[i].y - cities[j].y) * (cities[i].y - cities[j].y));
 45             cityMatrix[j][i] = cityMatrix[i][j];
 46         }
 47 
 48     }
 49 }
 50 
 51 
 52 //calculate the path-lenght of each path
 53 double GenticTSP::lenOfUnit(unit &unit)
 54 {
 55     unit.length = 0;
 56     for(int j = 0; j < CITIES - 1; ++j)
 57     {
 58         unit.length += cityMatrix[unit.path[j]][unit.path[j + 1]];
 59     }
 60 
 61     //回到起始城市
 62     unit.length += cityMatrix[unit.path[0] ][unit.path[CITIES - 1] ];
 63 
 64     return unit.length;
 65 }
 66 
 67 
 68 //init group of various paths
 69 void GenticTSP::initGroup()
 70 {
 71     vector<int> tmp;
 72     for(int i = 0; i < CITIES; ++i)
 73         tmp.push_back(i);
 74 
 75     for(int i = 0; i < UNITS; ++i)
 76     {
 77         random_shuffle(tmp.begin(),tmp.end());
 78         group[i].path = tmp;
 79         group[i].length = lenOfUnit(group[i]);
 80     }
 81 }
 82 
 83 //for test
 84 void printlist(list<int> &path)
 85 {
 86     for(list<int>::iterator it = path.begin(); it != path.end(); ++it){
 87         cout << *it << " ";    
 88     }
 89     cout << endl;
 90 }
 91 
 92 void rightRotateList(list<int> &path, list<int>::iterator ptr, list<int>::iterator res)
 93 {
 94     path.insert(ptr, res, path.end());
 95     path.erase(res, path.end());
 96 }
 97 
 98 
 99 void GenticTSP::selectGroup()
100 {
101     int selected = UNITS * ps_;
102     int non_selected = UNITS - selected; //防止取整丢失,所以直接采用减去selected
103     for(int i = 0; i < UNITS; ++i)
104     {
105         group[i].length = lenOfUnit(group[i]);
106     }
107     sort(group, group + UNITS);
108 
109     /*群体规模保持不变
110      *被淘汰的个体数目为non_selected
111      *用被选择的前non_seleted个个体替代之
112      */
113     for(int i = 0; i < non_selected; ++i)
114     {
115         group[UNITS-1-i].path =  group[i].path;
116         group[UNITS-1-i].length =  group[i].length;
117 
118        /* WARNING:
119         * error:memcpy(&group[UNITS-1-i], &group[i], sizeof(unit)); 
120         * 不能用memcpy
121         * 因为unit是自定义的结构体
122         * 其中的vector类型也不是原生的数据类型
123         * 如若使用,需要自定义构造函数
124         */
125     }
126 }
127 
128 
129 void GenticTSP::evoluteGroup()
130 {
131     for(int i = 0; i < MAX_GEN; ++i)
132     {
133         selectGroup();
134 
135         for(int j = 0; j < UNITS-2;)
136         {
137             crossUnits(group[j], group[j+1], group[j+2]);
138             j += 2;
139         }
140 
141         mutateGroup();
142     }
143 
144 }
145 
146 
147 void GenticTSP::mutateGroup()
148 {
149     srand(time(NULL));
150     int num;
151     int pos1, pos2;
152     int tmp;
153     int sum = UNITS * pm_; //变异的总数= 群体数 * 变异概率
154     while(sum--)
155     {
156         //随机选取一个发生变异的unit
157         num = rand() % UNITS;
158         //随机选取两个path上变异的城市,采用交换两个城市的方法进行变异
159         pos1 = rand() % CITIES;
160         pos2 = rand() % CITIES;
161 
162         //如果相同则不能算是变异,这里用while确保变异
163         while(pos1 == pos2)
164             pos2 = rand() % CITIES;
165 
166         tmp = group[num].path[pos1];
167         group[num].path[pos1] = group[num].path[pos2];
168         group[num].path[pos2] = tmp;
169 
170         //更新该变异后path的长度
171         lenOfUnit(group[num]);      
172     }
173 }
174 
175 
176 
177 
178 void GenticTSP::crossUnits(unit &u1, unit &u2, unit &u3)
179 {
180     //将路径存储在list类型的容器中便于后面的插入操作
181     list<int> path1(u1.path.begin(), u1.path.end());
182     list<int> path2(u2.path.begin(), u2.path.end());
183     list<int> path3(u3.path.begin(), u3.path.end());
184     //随机产生起始城市的id, 并将位置默认为第一个位置
185     srand((int)time(0));
186     int cityID = rand() % CITIES;
187     list<int>::iterator res1, res2, res3;
188     res1 = find(path1.begin(), path1.end(), cityID);
189     res2 = find(path2.begin(), path2.end(), cityID);
190     res3 = find(path3.begin(), path3.end(), cityID);
191     if(res1 == path1.end() || res2 == path2.end() || res3 == path3.end())
192     {
193         cout << "city not found" << endl;
194     }
195     
196     //将以随机选取的城市及其后面的城市右旋到序列首部
197     rightRotateList(path1, path1.begin(), res1);
198     rightRotateList(path2, path2.begin(), res2);
199     rightRotateList(path3, path3.begin(), res3);
200 
201     list<int>::iterator ptr1, ptr2, ptr3;
202     ptr1 = path1.begin();
203     ptr2 = path2.begin();
204     ptr3 = path3.begin();
205 
206     /*CITIES个城市
207      *第一个城市在循环体外已经确定
208      *循环体内只要再执行CITIES - 2 次即可
209      *因为当执行倒数第二次后,最后一个也就是仅剩的一个也无需再循环了
210      */
211     for(int k = 1; k < CITIES-1; ++k)
212     {
213       //  cout << "______" << k<< "______" << endl;
214         int h1 = *ptr1;
215         double len1 = cityMatrix[h1][*(++ptr1)];
216         int h2 = *ptr2;
217         double len2 = cityMatrix[h2][*(++ptr2)];
218         int h3 = *ptr3;
219         double len3 = cityMatrix[h3][*(++ptr3)];
220 
221         //找出前两个城市距离最小的那个path中得第一个城市的编号
222         double len = (len1 <= len2) ? len1 : len2;
223         len = (len < len3) ? len : len3;
224         if(len == len1){
225             cityID = *ptr1;
226         }else if(len == len2){
227             cityID = *ptr2;
228         }else{
229             cityID = *ptr3;
230         }
231 
232         //与当前城市距离最小的下一个城市编号为cityID
233         res1 = find(ptr1, path1.end(), cityID);
234         res2 = find(ptr2, path2.end(), cityID);
235         res3 = find(ptr3, path3.end(), cityID);
236         if(res1 == path1.end() || res2 == path2.end() || res3 == path3.end())
237         {
238             cout << "city not found in loop" << endl;
239         }
240         rightRotateList(path1, ptr1, res1);
241         rightRotateList(path2, ptr2, res2);
242         rightRotateList(path3, ptr3, res3);
243 
244         //指针失效,需要重新定位
245         ptr1 = find(path1.begin(), path1.end(), cityID);
246         ptr2 = find(path2.begin(), path2.end(), cityID);
247         ptr3 = find(path3.begin(), path3.end(), cityID);
248     }
249 
250 
251     /*为了避免三个路径相同,所以这里在不改变路径的情况下替换起点城市,有利于接下来的交叉*/
252     cityID = (rand() % CITIES);
253     res2 = find(path2.begin(), path2.end(), cityID);
254     rightRotateList(path2, path2.begin(), res2);
255 
256     cityID = (rand() % CITIES);
257     res3 = find(path3.begin(), path3.end(), cityID);
258     rightRotateList(path3, path3.begin(), res3);
259 
260     //交叉完之后再赋值给vector类型
261     u1.path.assign(path1.begin(), path1.end());
262     u2.path.assign(path2.begin(), path2.end());
263     u3.path.assign(path3.begin(), path3.end());
264 }
265     
266     
267 //print top5 paths with length
268 void GenticTSP::printBestUnit()
269 {
270     for(int i = 0; i < 5; ++i)
271     {
272         cout << "Path" << i << ": ";
273         for(vector<int>::iterator it = group[i].path.begin(); it != group[i].path.end(); ++it){
274             cout << *it << " ";    
275         }
276         cout << endl << "length: " << group[i].length << endl; 
277     }
278 }
GenticTsp.cpp

maintest.cpp

bubuko.com,布布扣
 1 #include <iostream>
 2 #include <string>
 3 #include <vector>
 4 #include <fstream>
 5 #include "GenticTSP.h"
 6 using namespace std;
 7 
 8 
 9 int main(int argc, const char *argv[])
10 {
11     GenticTSP genticTsp;
12     genticTsp.initMatrix("city.txt");
13     genticTsp.initGroup();
14     genticTsp.evoluteGroup();
15     genticTsp.selectGroup(); //进化后需要再一次选择,从而排序出最优序列
16     genticTsp.printBestUnit ();
17 
18     return 0;
19 }
maintest.cpp

city.txt

bubuko.com,布布扣
1  6  4 
  2 15 15 
  3 24 18 
  4 33 12 
  5 48 12 
  6 57 14 
  7 67 10 
  8 77 10 
  9 86 15 
 10  6 21 
 11 17 26 
 12 23 25 
 13 32 35 
 14 43 23 
 15 55 35 
 16 65 36 
 17 78 39 
 18 87 35 
 19  3 53 
 20 12 44 
 21 28 53 
 22 33 49 
 23 47 46 
 24 55 52 
 25 64 50 
 26 71 57 
 27 87 57 
 28  4 72 
 29 15 78 
 30 22 70 
 31 34 71 
 32 42 79 
 33 54 77 
 34 66 79 
 35 78 67 
 36 87 73 
 37  7 81 
 38 17 95 
 39 26 98 
 40 32 97 
 41 43 88 
 42 57 89 
 43 64 85 
 44 78 83 
 45 83 98 
 46  5 109 
 47 13 111 
 48 25 102 
 49 38 119 
 50 46 107 
 51 58 110 
 52 67 110 
 53 74 113 
 54 88 110 
 55  2 124 
 56 17 134 
 57 23 129 
 58 36 131 
 59 42 137 
 60 53 123 
 61 63 135 
 62 72 134 
 63 87 129 
 64  2 146 
 65 16 147 
 66 25 153 
 67 38 155 
 68 42 158 
 69 57 154 
 70 66 151 
 71 73 151 
 72 86 149 
 73  5 177 
 74 13 162 
 75 25 169 
 76 35 177 
 77 46 172 
 78 54 166 
 79 65 174 
 80 73 161 
 81 86 162 
 82  2 195 
 83 14 196 
 84 28 189 
 85 38 187 
 86 46 195 
 87 57 194 
 88 63 188 
 89 77 193 
 90 85 194 
 91  8 211 
 92 12 217 
 93 22 210 
 94 34 216 
 95 47 203 
 96 58 213 
 97 66 206 
 98 78 210 
 99 85 204 
city.txt

 

用的city.txt这里的数据,据说最优路径代价是1100+,可是我用我的选择,变异,交叉方法目前来看最小代价只能达到1500+。

 

遗传算法解决旅行商问题GA_TSP

标签:style   blog   http   io   ar   color   os   使用   sp   

原文地址:http://www.cnblogs.com/beatrice7/p/4142568.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!