Skip to content

Commit 95e9008

Browse files
committed
优化了算法并补充了实验内容
1 parent 3203e86 commit 95e9008

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+518
-31
lines changed

GTSP_instance.md

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
##### 1. GTSP(9,5)
2+
3+
| 物品 | 城市(编号,坐标) |
4+
| ----- | ----------------------------------------- |
5+
| 物品1 | [[0,[78, 34]], [1,[16, 56]] |
6+
| 物品2 | [[2,[98, 23]] |
7+
| 物品3 | [[3,[34, 15]], [4,[79, 46]], [5,[67,51]] |
8+
| 物品4 | [[6,[86, 13]], [7,[99, 46]] |
9+
| 物品5 | [[8,[47, 83]] |
10+
11+
##### 2. GTSP(17,11)
12+
13+
| 物品 | 城市(编号,坐标) |
14+
| ------ | ----------------------------------------- |
15+
| 物品1 | [[0,[78, 34]], [1,[16, 56]] |
16+
| 物品2 | [[2,[98, 23]] |
17+
| 物品3 | [[3,[34, 15]], [4,[79, 46]], [5,[67,51]] |
18+
| 物品4 | [[6,[86, 13]], [7,[99, 46]] |
19+
| 物品5 | [[8,[47, 83]] |
20+
| 物品6 | [[ 9,[34, 55]], [10,[ 9, 21]] |
21+
| 物品7 | [[11,[45, 45]], [12,[100,34]] |
22+
| 物品8 | [[13,[88, 90]] |
23+
| 物品9 | [[14,[ 4, 51]] |
24+
| 物品10 | [[15,[73, 11]] |
25+
| 物品11 | [[16,[56, 37]] |
26+
27+
##### 3.GTSP (24,15)
28+
29+
| 物品 | 城市(编号,坐标) |
30+
| ------ | ----------------------------------------- |
31+
| 物品1 | [[0,[78, 34]], [1,[16, 56]] |
32+
| 物品2 | [[2,[98, 23]] |
33+
| 物品3 | [[3,[34, 15]], [4,[79, 46]], [5,[67,51]] |
34+
| 物品4 | [[6,[86, 13]], [7,[99, 46]] |
35+
| 物品5 | [[8,[47, 83]] |
36+
| 物品6 | [[ 9,[34, 55]], [10,[ 9, 21]] |
37+
| 物品7 | [[11,[45, 45]], [12,[100,34]] |
38+
| 物品8 | [[13,[88, 90]] |
39+
| 物品9 | [[14,[ 4, 51]] |
40+
| 物品10 | [[15,[73, 11]],[16,[26, 27]] |
41+
| 物品11 | [[17,[56, 37]] |
42+
| 物品12 | [[18,[100,13]], [19,[101,20]] |
43+
| 物品13 | [[20,[90, 87]], [21,[90, 87]] |
44+
| 物品14 | [[22,[ 1, 1]] |
45+
| 物品15 | [[23,[71, 33]] |
46+
47+
##### 4.GTSP (31,16)
48+
49+
| 物品 | 城市(编号,坐标) |
50+
| ------ | ----------------------------------------- |
51+
| 物品1 | [[0,[78, 34]], [1,[16, 56]] |
52+
| 物品2 | [[2,[98, 23]] |
53+
| 物品3 | [[3,[34, 15]], [4,[79, 46]], [5,[67,51]] |
54+
| 物品4 | [[6,[86, 13]], [7,[99, 46]] |
55+
| 物品5 | [[8,[47, 83]] |
56+
| 物品6 | [[ 9,[34, 55]], [10,[ 9, 21]] |
57+
| 物品7 | [[11,[45, 45]], [12,[100,34]] |
58+
| 物品8 | [[13,[88, 90]] |
59+
| 物品9 | [[14,[ 4, 51]], [15,[18, 52]] |
60+
| 物品10 | [[16,[73, 11]], [17,[26, 27]] |
61+
| 物品11 | [[18,[56, 37]], [19,[27, 70]], [20,[16, 16]] |
62+
| 物品12 | [[21,[100,13]], [22,[101,20]] |
63+
| 物品13 | [[23,[90, 87]], [24,[90, 87]] |
64+
| 物品14 | [[25,[10, 10]], [26,[ 1, 1]] |
65+
| 物品15 | [[27,[7, 13]], [28,[17, 23]], [29,[71, 33]] |
66+
| 物品16 | [30,[100,25]] |
67+
68+
##### 5.GTSP(39,25)
69+
| 物品 | 城市(编号,坐标) |
70+
| ------ | ----------------------------------------- |
71+
|物品1| [[ 0,[78, 34]], [ 1,[16, 56]] |
72+
|物品2 |[[ 2,[98, 23]] |
73+
|物品3 |[[ 3,[34, 15]], [ 4,[79, 46]], [ 5,[67,51]] |
74+
|物品4 |[[ 6,[86, 13]], [ 7,[99, 46]] |
75+
|物品5 |[[ 8,[47, 83]], |
76+
|物品6 |[[ 9,[34, 55]], [10,[ 9, 21]], |
77+
|物品7 |[[11,[45, 45]], [12,[100,34]], |
78+
|物品8 |[[13,[88, 90]], |
79+
|物品9 |[[14,[ 4, 51]], [15,[18, 52]], |
80+
|物品10 |[[16,[73, 11]], [17,[26, 27]], |
81+
|物品11 |[[18,[56, 37]], [19,[27, 70]], |
82+
|物品12 |[[20,[100,13]], [21,[120,20]], |
83+
|物品13 |[[22,[90, 87]], [23,[90, 87]], |
84+
|物品14 |[[24,[10, 10]], |
85+
|物品15 |[[25,[7, 13]], |
86+
|物品16 |[[26,[ 90,75]], |
87+
|物品17 |[[27,[ 10,99]], |
88+
|物品18 |[[28,[103,105]], |
89+
|物品19 |[[29,[ 61,61]], [30,[ 51,51]], |
90+
|物品20 |[[31,[100, 5]], |
91+
|物品21 |[[32,[ 50,25]], |
92+
|物品22 |[[33,[ 50,50]], |
93+
|物品23 |[[34,[ 10,20]], |
94+
|物品24 |[[35,[ 31,20]], [36,[30,26]], [37,[34,35]] |
95+
|物品25 |[[38,[ 48,25]], |

README.md

+79-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,80 @@
1-
# :vertical_traffic_light: 启发式算法解决广义旅行商问题
1+
:vertical_traffic_light: 启发式算法解决广义旅行商问题
22

3+
#### 简介
4+
5+
使用 <u>模拟退火</u>、<u>禁忌搜索</u>、<u>遗传算法</u>和<u>蚁群算法</u>共四种启发式算法来解决**广义旅行商问题**
6+
7+
#### 问题实例
8+
9+
[问题实例链接](./GTSP_instance.md)
10+
11+
- GTSP(9,5) GTSP(17,11) GTSP(24,15) GTSP(31,16) GTSP(39,25)
12+
13+
#### 算法流程
14+
15+
![流程图](./images/process_total.jpg)
16+
17+
#### 结果分析
18+
19+
##### 复杂度
20+
21+
> 针对五种GTSP实例,分别迭代100000次,计算其运行时间
22+
23+
| 时间\s | 遗传算法 | 蚁群算法 | 模拟退火 | 禁忌搜索 |
24+
| ---- | -------- | -------- | -------- | -------- |
25+
|**GTSP(9,5)**| 215.1 | 1135.8 | 23.75 | 41.35 |
26+
|**GTSP(17,11)**| 291.5 | 4629.4 | 25.61 | 336.3 |
27+
|**GTSP(24,15)**| 416.3 | 8874.4 | 37.50 | 510.8 |
28+
|**GTSP(31,16)**| 522.7 | 11344.5 | 40.08 | 730.5 |
29+
|**GTSP(39,25)**| 617.2 | 15768.9 | 57.90 | 1624.0 |
30+
|平均 | 412.56 | 8,350.6 | 36.97 | 648.58 |
31+
32+
33+
34+
##### 收敛性
35+
36+
> 针对五种GTSP实例,分别迭代100000次,查看其每次迭代解的路径总距离
37+
38+
###### GTSP(9,5)
39+
40+
![](./images/iteration_9_5.jpg)
41+
42+
###### GTSP(17,11)
43+
44+
![](./images/iteration_17_11.jpg)
45+
46+
###### GTSP(24,15)
47+
48+
![](./images/iteration_24_15.jpg)
49+
50+
###### GTSP(31,16)
51+
52+
![](./images/iteration_31_16.jpg)
53+
54+
###### GTSP(39,25)
55+
56+
![](./images/iteration_39_25.jpg)
57+
58+
##### 解比较
59+
60+
> 针对五种GTSP实例,分别迭代100000次,查看最后解的效果
61+
62+
###### GTSP(9,5)
63+
64+
![](./images/solution_9_5.jpg)
65+
66+
###### GTSP(17,11)
67+
68+
![](./images/solution_17_11.jpg)
69+
70+
###### GTSP(24,15)
71+
72+
![](./images/solution_24_15.jpg)
73+
74+
###### GTSP(31,16)
75+
76+
![](./images/solution_31_16.jpg)
77+
78+
###### GTSP(39,25)
79+
80+
![](./images/solution_39_25.jpg)

algorithms/AntColonyAlgorithm.py

+37-19
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,10 @@ def _remove_same_group_city(self,citys,choose):
4343
for group in self.TSP.city_index_groups:
4444
if choose in group:
4545
for city in group:
46-
try:
47-
citys.remove(city)
48-
except Exception as e:
49-
print(city,citys,group)
50-
raise e
46+
citys.remove(city)
5147
return citys
52-
48+
49+
5350

5451
def solve(self, record_step=100):
5552
''' 执行蚁群算法'''
@@ -62,6 +59,12 @@ def solve(self, record_step=100):
6259
pheromone_mat=np.ones((citys_num,citys_num)) # 信息素浓度矩阵 初始为1
6360
path_mat=np.zeros((self.ants_num,items_num)).astype(int) # 路径矩阵
6461

62+
# 选择初始点
63+
#!注意只适合有一个物品只有一个城市有的情况
64+
begin=random.choice([x[0] for x in self.TSP.city_index_groups if len(x)==1])
65+
66+
67+
6568
star_t=time.time()
6669

6770
print("======================[ AC ]===========================")
@@ -71,7 +74,9 @@ def solve(self, record_step=100):
7174
#1.=== 随机放置蚂蚁 并让所有蚂蚁爬行完毕 ====
7275
for ant in range(self.ants_num):
7376
unvisit_list=list(range(citys_num)) # 未访问的
74-
choose=random.choice(unvisit_list) # 初始随机的放置蚂蚁
77+
78+
# choose=random.choice(unvisit_list) # 版本一 初始随机的放置蚂蚁
79+
choose=begin # 版本二 选择固定的起点
7580
unvisit_list=self._remove_same_group_city(unvisit_list,choose) # 移除有同类物品的城市
7681

7782
# 记录开始城市
@@ -80,10 +85,12 @@ def solve(self, record_step=100):
8085
for j in range(1,items_num):
8186
#轮盘法选择下一个城市
8287
trans_list,trans=[],0
83-
for k in range(len(unvisit_list)):
88+
for k in unvisit_list:
8489
# 计算概率 与信息素浓度成正比, 与距离成反比
85-
trans +=np.power(pheromone_mat[choose][unvisit_list[k]],self.alpha)*np.power(1.0/distMat[choose][k],self.beta)
90+
# print(pheromone_mat[choose][k],np.max(distMat[choose])/distMat[choose][k])
91+
trans +=np.power(pheromone_mat[choose][k],self.alpha)*np.power(np.max(distMat[choose])/distMat[choose][k],self.beta)
8692
trans_list.append(trans)
93+
# print(trans_list)
8794
rand=random.uniform(0,trans)#产生随机数
8895

8996
# 转一次轮盘 选择
@@ -103,20 +110,31 @@ def solve(self, record_step=100):
103110

104111
#所有蚂蚁的路径表填满之后,算每只蚂蚁的总距离
105112
dis_all_ant_list=self.cal_path_distance(path_mat)
113+
min_distance=min(dis_all_ant_list)
114+
min_path=path_mat[dis_all_ant_list.index(min_distance)].copy()
106115

107116
#3.=========== 更新信息素矩阵 ==============
108117
pheromone_change=np.zeros((citys_num,citys_num))
109-
for i in range(self.ants_num):
110-
# 在路径上的每两个相邻城市间留下信息素,与路径距离反比
111-
for j in range(items_num-1):
112-
pheromone_change[path_mat[i,j]][path_mat[i,j+1]] += self.Q/distMat[path_mat[i,j]][path_mat[i,j+1]]
113-
pheromone_change[path_mat[i,items_num-1]][path_mat[i,0]] += self.Q/distMat[path_mat[i,items_num-1]][path_mat[i,0]]
114-
pheromone_mat=(1-self.Rho)*pheromone_mat+pheromone_change
118+
# 版本一 所有的都会增加
119+
# for i in range(self.ants_num):
120+
# # 在路径上的每两个相邻城市间留下信息素,与路径距离反比
121+
# for j in range(items_num-1):
122+
# pheromone_change[path_mat[i,j]][path_mat[i,j+1]] += self.Q*(np.max(distMat[path_mat[i,j]])/distMat[path_mat[i,j]][path_mat[i,j+1]])
123+
# pheromone_change[path_mat[i,items_num-1]][path_mat[i,0]] += self.Q*(np.max(distMat[path_mat[i,items_num-1]])/distMat[path_mat[i,items_num-1]][path_mat[i,0]])
124+
# pheromone_mat=(1-self.Rho)*pheromone_mat+pheromone_change
125+
126+
# # 版本二 只有最优路径的信息素才会增加
127+
if count == 0 or min_distance < dis_new:
128+
for i in range(0,len(min_path)-1):
129+
pheromone_change[min_path[i]][min_path[i+1]]+=self.Q
130+
pheromone_change[min_path[i+1]][min_path[0]]+=self.Q
131+
pheromone_mat=(1-self.Rho)*pheromone_mat+pheromone_change
132+
133+
115134

116135
#记录历史最佳值
117-
if count == 0 or min(dis_all_ant_list) < dis_new:
118-
dis_new=min(dis_all_ant_list)
119-
path_new=path_mat[dis_all_ant_list.index(dis_new)].copy()
136+
if count == 0 or min_distance < dis_new:
137+
dis_new,path_new=min_distance,min_path
120138
self.TSP.set_path(path_new)
121139

122140
# 记录迭代的值
@@ -127,7 +145,7 @@ def solve(self, record_step=100):
127145

128146
end_t=time.time()
129147

130-
print("=============[ path:{} cost:{} time:{:.4}s]===============".format(self.TSP.path,self.TSP.distance,end_t-star_t))
148+
print("=============[ path:{} cost:{} time:{:.5}s]===============".format(self.TSP.path,self.TSP.distance,end_t-star_t))
131149

132150
return self.TSP
133151

algorithms/GeneticAlgorithm.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,12 @@ def cross(self,pops):
8686
# 必须产生新的
8787
p,q=random.randint(0,len(self.TSP.city_index_groups)-1),random.randint(0,len(self.TSP.city_index_groups)-1)
8888
pop[p],pop[q]=pop[q],pop[p] # 第一次交叉
89+
m,n=random.randint(0,len(self.TSP.city_index_groups)-1),random.randint(0,len(self.TSP.city_index_groups)-1)
90+
pop[m],pop[n]=pop[n],pop[m] # 第二次交叉
8991
# m,n=random.randint(0,len(self.TSP.city_index_groups)-1),random.randint(0,len(self.TSP.city_index_groups)-1)
90-
# pop[m],pop[n]=pop[n],pop[m] # 第二次交叉
92+
# pop[m],pop[n]=pop[n],pop[m] # 第三次交叉
93+
# m,n=random.randint(0,len(self.TSP.city_index_groups)-1),random.randint(0,len(self.TSP.city_index_groups)-1)
94+
# pop[m],pop[n]=pop[n],pop[m] # 第四次交叉
9195
new_pops.append(pop)
9296
return new_pops
9397

algorithms/TabuSearch.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ def find_new_path(self,best_path):
3636
paths=[]
3737

3838
# 1. 第一类 交换城市顺序
39-
for i in range(1,len(best_path)-1):
39+
for i in range(1,len(best_path)):
4040
for j in range(i+1,len(best_path)):
41+
# j=i
42+
# while j==i: j=random.choice(list(range(len(best_path))))
4143
path=best_path.copy()
4244
path[i],path[j]=path[j],path[i]
4345
paths.append(path)
@@ -46,8 +48,9 @@ def find_new_path(self,best_path):
4648
for i in range(len(best_path)):
4749
for group in self.TSP.city_index_groups:
4850
if best_path[i] in group:
49-
group.remove(best_path[i]) # 移除自己
50-
for other_city in group:
51+
group_copy=group.copy()
52+
group_copy.remove(best_path[i]) # 移除自己
53+
for other_city in group_copy:
5154
path=best_path.copy()
5255
path[i]=other_city
5356
paths.append(path)
@@ -93,7 +96,7 @@ def solve(self, record_step=100):
9396
elif best_path in self.taboo_table:
9497
#2.2===大于期望 且最优解在禁忌表===
9598
# 选择不在禁忌表中的最优解
96-
while best_path in self.taboo_table:
99+
while best_path in self.taboo_table :
97100
paths.remove(best_path)
98101
best_dist,best_path=self.find_best_dist_path(paths)
99102

0 commit comments

Comments
 (0)