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

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

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

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

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

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

genticTsp.h 代码如下:

 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代码如下:

  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

 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

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+。

时间: 2024-08-30 10:41:47

遗传算法解决旅行商问题GA_TSP的相关文章

【高级算法】遗传算法解决3SAT问题(C++实现)

转载请注明出处:http://blog.csdn.net/zhoubin1992/article/details/46910079 1 SAT问题描写叙述 命题逻辑中合取范式 (CNF) 的可满足性问题 (SAT)是当代理论计算机科学的核心问题, 是一典型的NP 全然问题.在定义可满足性问题SAT之前,先引进一些逻辑符号. 一个 SAT 问题是指: 对于给定的 CNF 是否存在一组关于命题变元的真值指派使A为真. 显然,如A为真,则CNF的每一个子句中必有一个命题变元为1(真). 2 遗传算法

遗传算法解决3SAT问题(C++实现代码)

1 SAT问题描述 命题逻辑中合取范式 (CNF) 的可满足性问题 (SAT)是当代理论计算机科学的核心问题, 是一典型的NP 完全问题.在定义可满足性问题SAT之前,先引进一些逻辑符号. 一个 SAT 问题是指: 对于给定的 CNF 是否存在一组关于命题变元的真值指派使A为真. 显然,如A为真,则CNF的每个子句中必有一个命题变元为1(真). 2 遗传算法 遗传算法类似于自然进化,通过作用于染色体上的基因寻找好的染色体来求解问题.与自然界相似,遗传算法对求解问题的本身一无所知,它所需要的仅是对

模拟退火算法解决旅行商问题(matlab)

模拟退火算法解决旅行商问题. 根据概率产生新解主要包含两个途径:二交换和三交换 二交换是在TSP回路中选择两个城市直接交换 三交换是在TSP回路中选择三个点,p1,p2,p3,然后将p1,p2之间的城市直接与p3之前对应长度的城市交换 这里产生新解的方法不唯一,只要能够保证产生的新解可以包含最优解所在的解空间即可 是否接受新解主要包含两种情况: 新解比历史最优解好,则百分百接受新解 新解比当前解好,没历史最优解好,则以一定概率接受新解,并且随着温度的降低.接受的概率也会降低. 如下是TSP代码.

tsp问题——遗传算法解决

TSP问题最简单的求解方法是枚举法.它的解是多维的.多局部极值的.趋于无穷大的复杂解的空间,搜索空间是n个点的所有排列的集合,大小为(n-1)!.可以形象地把解空间看成是一个无穷大的丘陵地带,各山峰或山谷的高度即是问题的极值.求解TSP,则是在此不能穷尽的丘陵地带中攀登以达到山顶或谷底的过程. 这一篇将用遗传算法解决TSP问题. 1)评价.这个评价算法应该比较简单了,就是找计算总距离,小的为优.目标函数转化为适应度函数可以取倒数. 2)突变.为了防止重复访问,不能随机的进行突变.因为每个城市只能

遗传算法解决0-1背包问题

1 import numpy 2 import matplotlib.pyplot as plt 3 4 5 data = numpy.array([[77, 92], 6 [22, 22], 7 [29, 87], 8 [50, 46], 9 [99, 90]]) 10 11 12 class GA(object): 13 """ 14 遗传算法解决0-1背包问题 15 """ 16 17 def __init__(self, length,

遗传算法解决TSP问题

1实验环境 实验环境:CPU [email protected],内存6G,windows7 64位操作系统 实现语言:java (JDK1.8) 实验数据:TSPLIB,TSP采样实例库中的att48数据源 数据地址:http://comopt.ifi.uni-heidelberg.de/software/TSPLIB95/tsp/att48.tsp.gz TSPLIB是一个从各种来源和各种类型中产生的TSP及其相关问题的采样实例库,这里选取TSP采样实例库中的att48数据源,最优值为106

人工智能-遗传算法解决推箱子问题现实

原创作品,出自 "晓风残月xj" 博客,欢迎转载,转载时请务必注明出处(http://blog.csdn.net/xiaofengcanyuexj). 由于各种原因,可能存在诸多不足,欢迎斧正! 一.研究背景 推箱子游戏中的路径查找问题-给定一方格,求两点最短距离. 传统求两点最短路径的算法有: 1.通用的搜索算法 2.解决无负权边的带权有向图的单源最短路问题的Dijkstra算法 3.求解含负权边的带权有向图的单源最短路径问题的Bellman-Ford算法 4.Bellman-for

穷举法解决旅行商问题

一.问题描述 如图所示,一个旅行商从A点出发,需要不重复地走遍5个城市ABCDE,最后回到A.每个城市之间的花费(即权值)如图所示,现在要求找出一条总花费最小的路径,即权值和为最小的路径. 二.     算法说明 1.    算法一: 登山法(贪心法) 即在每一个城市出发前比较接下来所能走的城市花费(权值),找出权值最小的走. 优缺点:由于只是在每个城市局部地考虑权值最小,但当走完所用城市后,所得到权值和不一定为最小,所以采用此算法得不到精确解,但此算法复杂度较低. 2.  算法二:穷举法(本程

[数学建模(三)]遗传算法与旅行商问题

clc,clear sj=load('data3.txt') %加载敌方100 个目标的数据 x=sj(:,1); y=sj(:,2); d1=[70,40]; sj0=[d1;sj;d1]; %增加一个点[70,40]作为首尾 sj=sj0; d=zeros(102); %距离矩阵d % 通过向量化的方法计算距离矩阵 amount = size(sj,1); dist_matrix = zeros(amount, amount); coor_x_tmp1 = sj(:,1) * ones(1,