禁忌搜索算法求解TSP问题python实现
文章目录
- 1 禁忌搜索(Tabu Search)
- 1.1 TS相关术语介绍
- 1.2 算法流程
- 1.3 算例分析
- 2 TS设计
- 2.1 编码原则
- 2.2 数据准备
- 2.3 初始路径的生成
- 2.3.1 随机生成
- 2.3.2 改良圈算法
- 2.3.3 贪婪算法
- 2.4 交换法则
- 2.5 邻域设计
- 2.6 接受准则
- 2.7 新回路的生成
- 2.8 禁忌搜索
- 2.9 绘图
- 3 实验结果分析
- 4 附python源码(完整版)
1 禁忌搜索(Tabu Search)
1.1 TS相关术语介绍
- 邻域
对于组合优化问题,给定任意可行解x,x∈D,D是决策变量的定义域,对于D上的一个映射:N:x∈D→N(x)∈2(D) 其中2(D)表示D的所有子集组成的集合,N(x)成为x的一个邻域,y∈N(x)称为x的一个邻居。
- 候选集合
候选集合一般由邻域中的邻居组成,可以将某解的所有邻居作为候选集合,也可以通过最优提取,也可以随机提取,例如某一问题的初始解是[1,2,3],若通过两两交换法则生成候选集合,则可以是[1,3,2],[2,1,3],[3,2,1]中的一个或几个。
- 禁忌表
禁忌表包括禁忌对象和禁忌长度。由于在每次对当前解的搜索中,需要避免一些重复的步骤,因此将某些元素放入禁忌表中,这些元素在下次搜索时将不会被考虑,这些被禁止搜索的元素就是禁忌对象;
禁忌长度则是禁忌表所能接受的最多禁忌对象的数量,若设置的太多则可能会造成耗时较长或者算法停止,若太少则会造成重复搜索。
- 评价函数
用来评价当前解的好坏,TSP问题中是路径里程。
- 藐视规则
禁忌搜索算法中,迭代的某一步会出现候选集的某一个元素被禁止搜索,但是若解禁该元素,则会使评价函数有所改善,因此我们需要设置一个特赦规则,当满足该条件时该元素从禁忌表中跳出。
- 终止规则
一般当两次迭代得到的局部最优解不再变化,或者两次最优解的评价函数差别不大,或者迭代N次之后停止迭代,通常选择第三种方法。
1.2 算法流程
Step1:生成初始解(随机生成,贪婪算法生成,改良圈算法生成);
Step2:Inversion方法生成邻域;
Step3:更新当前最优解、禁忌表以及下一次进入迭代过程的路径;
Step4:重复Step2~3直到满足程序终止条件(本实验采用迭代次数);
Step5:搜索结果可视化输出。
1.3 算例分析
tabu_size=2tabu\_size=2tabu_size=2(禁忌表长)
S1=[2,1,4,3]S_1=[2,1,4,3]S1=[2,1,4,3],$ f(S_1) = 500,,,tabu_list =[] ,,,S_0 = [2,1,4,3],best_so_far=500$
随机交换S0S_0S0中两个元素的位置,一共不重复地交换M(候选集合长度)次
交换元素 | 候选集合(邻域) | 目标函数值 |
---|---|---|
(2 , 1) | [1,2,3,4] | 480 |
(1 , 4) | [2,4,1,3] | 436 |
(4 , 3) | [2,1,3,4] | 652 |
对S0S_0S0交换1和4时目标函数值最优,此时S2=[2,4,1,3]S_2=[2,4,1,3]S2=[2,4,1,3],f(S2)=436f(S_2)=436f(S2)=436。将(1,4)添加到禁忌表中,tabu_list=[(1,4)]tabu\_list=[(1,4)]tabu_list=[(1,4)],令S0=S2,best_so_far=436S_0=S_2,best\_so\_far=436S0=S2,best_so_far=436。随机交换S2S_2S2中两个元素的位置,总共不重复地交换M次
交换元素 | 候选集合(邻域) | 目标函数值 |
---|---|---|
(2 , 4) | [4,2,1,3] | 460 |
(4 , 1) | [2,1,4,3] | 500 |
(1 , 3) | [2,4,3,1] | 608 |
对S2S_2S2交换2和4时目标函数值最优,此时S3=[4,2,1,3]S_3=[4,2,1,3]S3=[4,2,1,3],S0S_0S0和best_so_farbest\_so\_farbest_so_far保持不变f(S3)=460f(S_3)=460f(S3)=460。将(2,4)添加到禁忌表中,tabu_list=[(1,4),(2,4)]tabu\_list=[(1,4),(2,4)]tabu_list=[(1,4),(2,4)]。随机交换S2中两个元素的位置,总共不重复地交换M次。
交换元素 | 候选集合(邻域) | 目标函数值 |
---|---|---|
(4 , 2) | [2,4,1,3] | 436 |
(2 , 1) | [4,1,2,3] | 440 |
(1 , 3) | [4,2,3,1] | 632 |
对S3S_3S3交换4和2时目标函数最优,虽然(2,4)已经在禁忌表中,但是f(S3)=436<best_so_far=460f(S_3)=436<best\_so\_far=460f(S3)=436<best_so_far=460,所以此时只需将禁忌表中的元素(2,4)调整一下位置即可(放在现有元素的最后面)。此时S4=[2,4,1,3]S_4=[2,4,1,3]S4=[2,4,1,3],f(S4)=436f(S_4)=436f(S4)=436,tabu_list=[(2,4),(1,4)]tabu\_list=[(2,4),(1,4)]tabu_list=[(2,4),(1,4)]。⋯\cdots⋯不断迭代直到达到迭代终止条件。
2 TS设计
2.1 编码原则
采用自然数编码,每一个城市用唯一的一个自然数表示。
如【1、2、3、4、5、6、7】表示7个城市的编号
2.2 数据准备
- 从txt文档中录入城市信息(城市编号及其坐标)
filename = '算例\\eil101.txt'
city_num = [] #城市编号
city_location = [] #城市坐标
with open(filename, 'r') as f:datas = f.readlines()[6:-1]
for data in datas:data = data.split()city_num.append(int(data[0]))x = float(data[1])y = float(data[2])city_location.append((x,y))#城市坐标
- 程序需要使用到的常数
city_count = len(city_num) #总的城市数
origin = 1 #起点和终点城市
remain_cities = city_num[:]
remain_cities.remove(origin) #迭代过程中变动的城市
remain_count = city_count - 1
- 计算城市距离的邻接矩阵,距离采用欧式距离
dis =[[0]*city_count for i in range(city_count)] #初始化
for i in range(city_count):for j in range(city_count):if i != j:dis[i][j] = math.sqrt((city_location[i][0]-city_location[j][0])**2 + (city_location[i][1]-city_location[j][1])**2)else:dis[i][j] = 0
- 计算路径的里程成本
def route_mile_cost(route):''':param route:运行路线'''mile_cost = 0.0mile_cost += dis[origin-1][route[0]-1]#从起始点开始for i in range(remain_count-1):#路径的长度mile_cost += dis[route[i]-1][route[i+1]-1]mile_cost += dis[route[-1]-1][origin-1] #到终点结束return mile_cost
2.3 初始路径的生成
2.3.1 随机生成
输入需要调整位置的城市序列,使用random库中的shuffle方法随机排列,输出初始路径及其对应的里程。
def random_initial_route(remain_cities):'''随机生成初始路径'''initial_route = remain_cities[:]random.shuffle(initial_route)mile_cost = route_mile_cost(initial_route)return initial_route,mile_cost
2.3.2 改良圈算法
先随机生成路径R如【1、5、6、4、2、3、7、1】形成一个Hamilton圈。随机交换两个点(起点和终点除外)的位置,若交换后路径CR的里程小于交换前路径R的里程,则接受此次交换,令R = CR,否则重新交换,直到成功交换次数达到设置的改良次数。
例1:回路R=V1V2⋯Vi−1ViVi+1⋯Vj−1VjVj+1⋯VnV1R = V_1V_2\cdots V_{i-1}V_{i}V_{i+1}\cdots V_{j-1}V_{j}V_{j+1}\cdots V_nV_1R=V1V2⋯Vi−1ViVi+1⋯Vj−1VjVj+1⋯VnV1
随机选取两个点的位置(i,j)(i,j)(i,j),(1<i<j<n+1)
若有
dRi−1Rj+dRjRi+1+dRj−1Ri+dRiRj+1<dRi−1Ri+dRiRi+1+dRj−1Rj+dRjRj+1d_{R_{i-1}R_j}+d_{R_{j}R_{i+1}}+d_{R_{j-1}R_i}+d_{R_{i}R_{j+1}}<\\ d_{R_{i-1}R_i}+d_{R_{i}R_{i+1}}+d_{R_{j-1}R_j}+d_{R_{j}R_{j+1}} dRi−1Rj+dRjRi+1+dRj−1Ri+dRiRj+1<dRi−1Ri+dRiRi+1+dRj−1Rj+dRjRj+1
则接受此次交换改良。
回路R=V1V2⋯Vi−1VjVi+1⋯Vj−1ViVj+1⋯VnV1R = V_1V_2\cdots V_{i-1}V_{j}V_{i+1}\cdots V_{j-1}V_{i}V_{j+1}\cdots V_nV_1R=V1V2⋯Vi−1VjVi+1⋯Vj−1ViVj+1⋯VnV1
==注:==d表示城市之间的距离矩阵
例2:现有当前回路如下
随机选取两个点如(6,3)
交换两个点的位置并将两点之间的数据倒置
- 算法流程图:
- 代码实现
improve_count = 100 #改良次数
def improve_circle(remain_cities):'''改良圈算法生成初始路径'''initial_route = remain_cities[:]random.shuffle(initial_route)cost0 = route_mile_cost(initial_route)route = [1] + initial_route + [1]label = list(i for i in range(1,len(remain_cities)))j = 0while j < improve_count:new_route = route[:]index0,index1 = random.sample(label,2)new_route[index0],new_route[index1]= new_route[index1],new_route[index0]cost1 = route_mile_cost(new_route[1:-1])improve = cost1 - cost0if improve < 0: #交换两点后有改进route = new_route[:]cost0 = cost1j += 1else:continueinitial_route = route[1:-1]return initial_route,cost0
2.3.3 贪婪算法
算法思想:从当前城市CR出发找寻与其距离最短的城市NR并标记,令CR=NR,然后继续找寻与CR距离最近的城市并标记,直到所有城市被标记完。最后回到起点城市。
- 算法流程图:
- 代码实现
def nearest_city(current_city,cand_cities):'''找寻离当前城市最近的城市'''temp_min = float('inf')next_city = Nonefor i in range(len(cand_cities)):distance = dis[current_city-1][cand_cities[i]-1]if distance < temp_min:temp_min = distancenext_city = cand_cities[i]return next_city,temp_min
def greedy_initial_route(remain_cities):'''采用贪婪算法生成初始解从第一个城市出发找寻与其距离最短的城市并标记,然后继续找寻与第二个城市距离最短的城市并标记,直到所有城市被标记完。最后回到第一个城市(起点城市)'''cand_cities = remain_cities[:]current_city = originmile_cost = 0initial_route = []while len(cand_cities) > 0:next_city,distance = nearest_city(current_city,cand_cities) #找寻最近的城市及其距离mile_cost += distanceinitial_route.append(next_city) #将下一个城市添加到路径列表中current_city = next_city #更新当前城市cand_cities.remove(next_city) #更新未定序的城市mile_cost += dis[initial_route[-1]-1][0] #回到起点return initial_route,mile_cost
2.4 交换法则
对当前回路R随机选取两个点,倒置两点之间所有点的顺序,形成候选回路cand_route
例:当前回路R =【1、5、6、4、2、3、7、1】,随机选取的两个点如【3,5】
则交换后的回路为:
- 代码实现:
def random_swap_2_city(route):'''随机交换两个城市,并计算里程成本'''new_route = route[:]swap_2_city = random.sample(route,2)index = [0]*2index[0] = route.index(swap_2_city[0])index[1] = route.index(swap_2_city[1])index = sorted(index)swap_route = [0]*len(route)if index[0] != 0:new_route[index[0]:index[1]+1] = route[index[1]:index[0]-1:-1]else:swap_route[0] = route[0]swap_route[1:index[1]+1] = route[index[1]:0:-1]swap_route[index[1]+1:] = route[index[1]+1:]new_route = swap_route[:]return new_route,sorted(swap_2_city)
2.5 邻域设计
设置邻域规模candiate_routes_size = 700,表示邻域中能够容纳700条候选路径。
设置交换元素集合canidate_swap存储每次的换方式确保当前路径的邻域中无重复路径。
设置cand_mile_cost存储邻域中回路对应的里程。
流程图:
2.6 接受准则
将邻域中的路径按照里程大小升序排列。当前禁忌表如下
1、破禁法则:若邻域中的最优路径MR不差于当前最优路径CBR,即使MR对应的交换方式S已经存在禁忌表中,仍然接受其成为新的回路。令CBR = MR,并调整S在禁忌表中的位置
例:MR对应的S=【2,4】
调整S到禁忌表的末尾:
2、邻域中的最优路径MR不差于当前最优路径CBR。若MR对应的交换方式S未在禁忌表中,则令CBR = MR,并将其交换方式S添加到禁忌表中。反之,采用破禁法则。
例:MR对应的S = 【2,6】未在当前禁忌表中,将【2,6】添加到禁忌表中。
3、邻域中的最优路径劣于当前最优路径CBR。则选取升序排列的邻域路径中第一个交换方式S未在禁忌表中的路径LR。并将其交换方式S添加到禁忌表中。(==注:==选取的路径最多是邻域中的第tabu_size+1位)
例:邻域中的路径R1,R2,R3虽然都比R4更优,但是前三者对应的交换方式都已经存在禁忌表中,所以选择第一个交换方式未在禁忌表中的R4
邻域路径降序排列:
邻域路径对应的交换方式:
2.7 新回路的生成
领域设计和接受准则都是为了生成新的路径,因此可以将两者结合放在一个函数中。
def generate_new_route(route):'''生成新的路线'''global tabu_list,best_so_far_cost,best_so_far_routeglobal candiate_routes_size,tabu_sizecandidate_routes = [] #路线候选集合candidate_mile_cost = [] #候选集合路线对应的里程成本candidate_swap = [] #交换元素while len(candidate_routes) < candiate_routes_size:cand_route,cand_swap = random_swap_2_city(route)if cand_swap not in candidate_swap: #此次生成新路线的过程中,没有被交换过candidate_routes.append(cand_route)candidate_swap.append(cand_swap)candidate_mile_cost.append(route_mile_cost(cand_route))min_mile_cost = min(candidate_mile_cost)i = candidate_mile_cost.index(min_mile_cost)#如果此次交换集的最优值比历史最优值更好,则更新历史最优值和最优路线if min_mile_cost < best_so_far_cost:best_so_far_cost = min_mile_cost best_so_far_route = candidate_routes[i]new_route = candidate_routes[i]if candidate_swap[i] in tabu_list:tabu_list.remove(candidate_swap[i]) #藐视法则elif len(tabu_list) >= tabu_size:tabu_list.remove(tabu_list[0])tabu_list.append(candidate_swap[i])else:#此次交换集未找到更优路径,则选择交换方式未在禁忌表中的次优K = candiate_routes_sizestop_value = K - len(tabu_list) - 1while K > stop_value:min_mile_cost = min(candidate_mile_cost)i = candidate_mile_cost.index(min_mile_cost)#如果此次交换集的最优值比历史最优值更好,则更新历史最优值和最优路线if min_mile_cost < best_so_far_cost:best_so_far_cost = min_mile_cost best_so_far_route = candidate_routes[i]new_route = candidate_routes[i]if candidate_swap[i] in tabu_list:tabu_list.remove(candidate_swap[i]) #藐视法则elif len(tabu_list) >= tabu_size:tabu_list.remove(tabu_list[0])tabu_list.append(candidate_swap[i])breakelse:#此次交换集未找到更优路径,则选择交换方式未在禁忌表中的次优if candidate_swap[i] not in tabu_list:tabu_list.append(candidate_swap[i])new_route = candidate_routes[i]if len(tabu_list) > tabu_size:tabu_list.remove(tabu_list[0])breakelse:candidate_mile_cost.remove(min_mile_cost)candidate_swap.remove(candidate_swap[i])candidate_routes.remove(candidate_routes[i])K -= 1return new_route
2.8 禁忌搜索
- 流程图:
- 代码实现
def tabu_search(remain_cities,iteration_count=100):global tabu_list,best_so_far_cost,best_so_far_routebest_so_far_route,best_so_far_cost = greedy_initial_route(remain_cities)#贪婪算法生成初始解# best_so_far_route,best_so_far_cost = random_initial_route(remain_cities)#随机生成初始解#best_so_far_route,best_so_far_cost = improve_circle(remain_cities)#改良圈算法生成初始解new_route = best_so_far_route[:]#生成邻域空间for j in range(iteration_count):new_route = generate_new_route(new_route)#输出最终搜索结果final_route = [origin] + best_so_far_route +[origin]return final_route,best_so_far_cost
2.9 绘图
def main():time_start = time.time()N = 100 #迭代次数satisfactory_solution,mile_cost,record = tabu_search(remain_cities,N)time_end = time.time()print('time cost:',(time_end - time_start))print("优化里程成本:%d" %(int(mile_cost)))print("优化路径:\n",satisfactory_solution)#绘制路线图X = []Y = []for i in satisfactory_solution:x = city_location[i-1][0]y = city_location[i-1][1]X.append(x)Y.append(y)plt.plot(X,Y,'-o')plt.title("satisfactory solution of TS:%d"%(int(mile_cost)))plt.show()#绘制迭代过程图A = [i for i in range(N+1)]#横坐标B = record[:] #纵坐标plt.xlim(0,N)# plt.ylim(7500,record[0])plt.xlabel('迭代次数',fontproperties="SimSun")plt.ylabel('路径里程',fontproperties="SimSun")plt.title("solution of TS changed with iteration")plt.plot(A,B,'-')plt.show()if __name__ == '__main__':main()
3 实验结果分析
以算例berlin52为例,说明初始解对禁忌搜索算法的影响。
初始解分别采用随机生成,贪婪算法,改良圈算法三种方法各自进行10组实验,得出数据如下:
实验结果分析一:
贪婪算法和改良圈算法形成的初始解进行禁忌搜索的结果优于随机生成初始解的结果,并且在这10次实验中GTS的均值显著优于RTS,可见初始解对TS的最终效果有较大影响。此外,ITS虽然同样能够求得最优解,但是耗费的时间要多于RTS和GTS,这是因为改良圈算法的效率受改良次数的影响,如果要得到一个较好的初始解就需要增大改良次数。在初始解生成时间方面,改良圈算法并无优势。
以下是本次实验三种初始解生成方法下的禁忌搜索最优路径及其对应的迭代过程结果。
三种初始解生成方式下TS搜索的最优路径
迭代过程图:
一、初始解贪婪 二、初始解随机 三、初始解改良
实验结果分析二:
从以上三幅迭代流程图可以看出,禁忌搜索的收敛效率比较高,此外贪婪算法和改良圈算法形成初始解的情况下,TS的迭代过程都有一个缓冲平台。若迭代次数过少,则很容易陷入局部最优(即使随机生成初始解的情况也无例外)。
初始解采用贪婪算法对数据源:berlin52、eil101、ch150、fl417、dsj1000进行TS搜索求解
结果分析:小规模情况下150个数据点以内,TS搜索结果比较理想,gap值在5%以下。随着数据点数的增大,TS搜索结果越偏离最优解(gap值增大)。
4 附python源码(完整版)
import math,random,time
import matplotlib.pyplot as plt
#读取坐标文件
filename = '算例\\berlin52.txt'
city_num = [] #城市编号
city_location = [] #城市坐标
with open(filename, 'r') as f:datas = f.readlines()[6:-1]
for data in datas:data = data.split()city_num.append(int(data[0]))x = float(data[1])y = float(data[2])city_location.append((x,y))#城市坐标
city_count = len(city_num) #总的城市数
origin = 1 #设置起点和终点城市
remain_cities = city_num[:]
remain_cities.remove(origin) #迭代过程中变动的城市
remain_count = city_count - 1
#计算邻接矩阵
dis =[[0]*city_count for i in range(city_count)] #初始化
for i in range(city_count):for j in range(city_count):if i != j:dis[i][j] = math.sqrt((city_location[i][0]-city_location[j][0])**2 + (city_location[i][1]-city_location[j][1])**2)else:dis[i][j] = 0def route_mile_cost(route):'''计算路径的里程'''mile_cost = 0.0mile_cost += dis[origin-1][route[0]-1]#从起始点开始for i in range(remain_count-1):#路径的长度mile_cost += dis[route[i]-1][route[i+1]-1]mile_cost += dis[route[-1]-1][origin-1] #到终点结束return mile_costdef random_initial_route(remain_cities):'''随机生成初始路径'''initial_route = remain_cities[:]random.shuffle(initial_route)mile_cost = route_mile_cost(initial_route)return initial_route,mile_costimprove_count = 100 #改良次数
def improve_circle(remain_cities):'''改良圈算法生成初始路径'''initial_route = remain_cities[:]random.shuffle(initial_route)cost0 = route_mile_cost(initial_route)route = [1] + initial_route + [1]label = list(i for i in range(1,len(remain_cities)))j = 0while j < improve_count:new_route = route[:]#随机交换两个点index0,index1 = random.sample(label,2)new_route[index0],new_route[index1]= new_route[index1],new_route[index0] cost1 = route_mile_cost(new_route[1:-1])improve = cost1 - cost0if improve < 0: #交换两点后有改进route = new_route[:]cost0 = cost1j += 1else:continueinitial_route = route[1:-1]return initial_route,cost0#获取当前邻居城市中距离最短的1个
def nearest_city(current_city,cand_cities):temp_min = float('inf')next_city = Nonefor i in range(len(cand_cities)):distance = dis[current_city-1][cand_cities[i]-1]if distance < temp_min:temp_min = distancenext_city = cand_cities[i]return next_city,temp_min
def greedy_initial_route(remain_cities):'''采用贪婪算法生成初始解。从第一个城市出发找寻与其距离最短的城市并标记,然后继续找寻与第二个城市距离最短的城市并标记,直到所有城市被标记完。最后回到第一个城市(起点城市)'''cand_cities = remain_cities[:]current_city = originmile_cost = 0initial_route = []while len(cand_cities) > 0:next_city,distance = nearest_city(current_city,cand_cities) #找寻最近的城市及其距离mile_cost += distanceinitial_route.append(next_city) #将下一个城市添加到路径列表中current_city = next_city #更新当前城市cand_cities.remove(next_city) #更新未定序的城市mile_cost += dis[initial_route[-1]-1][0] #回到起点return initial_route,mile_costdef random_swap_2_city(route):'''随机选取两个城市并将这两个城市之间的点倒置,计算其里程成本'''new_route = route[:]swap_2_city = random.sample(route,2)index = [0]*2index[0] = route.index(swap_2_city[0])index[1] = route.index(swap_2_city[1])index = sorted(index)L = index[1] - index[0] + 1for j in range(L):new_route[index[0]+j] = route[index[1]-j]return new_route,sorted(swap_2_city)candiate_routes_size = 700 #邻域规模
tabu_size = 10
tabu_list = [] #禁忌表def generate_new_route(route):'''生成新的路线'''global tabu_list,best_so_far_cost,best_so_far_routeglobal candiate_routes_size,tabu_sizecandidate_routes = [] #路线候选集合candidate_mile_cost = [] #候选集合路线对应的里程成本candidate_swap = [] #交换元素while len(candidate_routes) < candiate_routes_size:cand_route,cand_swap = random_swap_2_city(route)if cand_swap not in candidate_swap: #此次生成新路线的过程中,没有被交换过candidate_routes.append(cand_route)candidate_swap.append(cand_swap)candidate_mile_cost.append(route_mile_cost(cand_route))min_mile_cost = min(candidate_mile_cost)i = candidate_mile_cost.index(min_mile_cost)#如果此次交换集的最优值比历史最优值更好,则更新历史最优值和最优路线if min_mile_cost < best_so_far_cost:best_so_far_cost = min_mile_cost best_so_far_route = candidate_routes[i]new_route = candidate_routes[i]if candidate_swap[i] in tabu_list:tabu_list.remove(candidate_swap[i]) #藐视法则elif len(tabu_list) >= tabu_size:tabu_list.remove(tabu_list[0])tabu_list.append(candidate_swap[i])else:#此次交换集未找到更优路径,则选择交换方式未在禁忌表中的次优K = candiate_routes_sizestop_value = K - len(tabu_list) - 1while K > stop_value:min_mile_cost = min(candidate_mile_cost)i = candidate_mile_cost.index(min_mile_cost)#如果此次交换集的最优值比历史最优值更好,则更新历史最优值和最优路线if min_mile_cost < best_so_far_cost:best_so_far_cost = min_mile_cost best_so_far_route = candidate_routes[i]new_route = candidate_routes[i]if candidate_swap[i] in tabu_list:tabu_list.remove(candidate_swap[i]) #藐视法则elif len(tabu_list) >= tabu_size:tabu_list.remove(tabu_list[0])tabu_list.append(candidate_swap[i])breakelse:#此次交换集未找到更优路径,则选择交换方式未在禁忌表中的次优if candidate_swap[i] not in tabu_list:tabu_list.append(candidate_swap[i])new_route = candidate_routes[i]if len(tabu_list) > tabu_size:tabu_list.remove(tabu_list[0])breakelse:candidate_mile_cost.remove(min_mile_cost)candidate_swap.remove(candidate_swap[i])candidate_routes.remove(candidate_routes[i])K -= 1return new_route,best_so_far_cost
def tabu_search(remain_cities,iteration_count=100):global tabu_list,best_so_far_cost,best_so_far_route#生成初始解best_so_far_route,best_so_far_cost = greedy_initial_route(remain_cities)# best_so_far_route,best_so_far_cost = random_initial_route(remain_cities)# best_so_far_route,best_so_far_cost = improve_circle(remain_cities)record = [best_so_far_cost] #记录每一次搜索后的最优值new_route = best_so_far_route[:]#生成邻域for j in range(iteration_count): new_route,best_so_far_cost = generate_new_route(new_route)record.append(best_so_far_cost)final_route = [origin] + best_so_far_route +[origin]return final_route,best_so_far_cost,record
def main():N = 100 #迭代次数time_start = time.time()satisfactory_solution,mile_cost,record = tabu_search(remain_cities,N)time_end = time.time()time_cost = time_end - time_startprint('time cost:',time_cost)print("优化里程成本:%d" %(int(mile_cost)))print("优化路径:\n",satisfactory_solution)#绘制路线图X = []Y = []for i in satisfactory_solution:x = city_location[i-1][0]y = city_location[i-1][1]X.append(x)Y.append(y)plt.plot(X,Y,'-o')plt.title("satisfactory solution of TS:%d"%(int(mile_cost)))plt.show()#绘制迭代过程图A = [i for i in range(N+1)]#横坐标B = record[:] #纵坐标plt.xlim(0,N)plt.xlabel('迭代次数',fontproperties="SimSun")plt.ylabel('路径里程',fontproperties="SimSun")plt.title("solution of TS changed with iteration")plt.plot(A,B,'-')plt.show()return int(mile_cost),time_costif __name__ == '__main__':main()
# M = 10
# Mcosts = [0]*M
# Tcosts = [0]*M
# for j in range(M):
# Mcosts[j],Tcosts[j] = main()
# AM = sum(Mcosts)/M #平均里程
# AT = sum(Tcosts)/M #平均时间
# print("最小里程:",min(Mcosts))
# print("平均里程:",AM)
# print('里程:\n',Mcosts)
# print("平均时间:",AT)
禁忌搜索算法求解TSP问题python实现相关推荐
- 实验10 禁忌搜索算法求解tsp问题
传送门(所有的实验都使用python实现) 实验1 BP神经网络实验 实验2 som网实验 实验3 hopfield实现八皇后问题 实验4 模糊搜索算法预测薄冰厚度 实验5 遗传算法求解tsp问题 实 ...
- 禁忌搜索算法求解TSP旅行商问题Matlab实现
一. 禁忌搜索算法 禁忌搜索算法是一种全局性邻域搜索算法,模拟人类具有记忆功能的寻优特征.它通过局部邻域搜索机制和相应的禁忌准则来避免迂回搜索,并通过破禁水平来释放一些被禁忌的优良状态,进而保证多样化 ...
- 遗传-粒子群算法遗传-禁忌搜索算法求解TSP问题
1. 前言 上一篇博文[五种常见启发式算法求解TSP问题-总结篇]中,总结了五种常见启发式算法在求解TSP问题上的效果,其中遗传算法的求解质量最差,而粒子群算法和禁忌搜索算法的求解效果最佳,因此本文计 ...
- 基于改进禁忌搜索算法求解TSP问题(Matlab代码实现)
目录 1 概述 2 改进禁忌搜索算法 3 运行结果 4 参考文献 5 Matlab代码实现 1 概述 当城市数量较少时,理论上可以通过穷举法来列举出最优方案,然而当城市数量较多时,所有路线之和将呈指数 ...
- 禁忌搜索算法求解TSP旅行商问题C++(2020.11.19)
TS算法求解TSP问题C++ 1.禁忌搜索算法 1.1 基本思想及主要特点 1.2 基本概念 1.3 算法流程 2. TS求解TSP问题的C++实现 2.1 输入数据文件:bayg29.tsp 2.2 ...
- 领域搜索算法java_使用JAVA实现算法——禁忌搜索算法解决TSP问题
packageBasePart;importjava.io.BufferedReader;importjava.io.FileInputStream;importjava.io.IOException ...
- python用禁忌搜索算法实现TSP旅行商问题
使用python禁忌搜索算法实现TSP旅行商问题 计算智能课程作业,使用python实现禁忌搜索算法实现TSP旅行商问题 问题简介: 给定一系列城市和每对城市之间的距离,求解访问每一座城市一次并回到起 ...
- 【TS TSP】基于matlab禁忌搜索算法求解31城市旅行商问题【含Matlab源码 1143期】
一.获取代码方式 获取代码方式1: 完整代码已上传我的资源:[TSP]基于matlab禁忌搜索算法求解31城市旅行商问题[含Matlab源码 1143期] 点击上面蓝色字体,直接付费下载,即可. 获取 ...
- 惩罚函数外点matlab,禁忌搜索算法求解带时间窗的车辆路径问题(惩罚函数版 附MATLAB代码)...
本周应小伙伴要求继续学习TS求VRPTW,不过这次通过使用惩罚约束的形式允许解违反时间窗约束和容量约束,不过要给违反约束的解加以惩罚. 这次我们的目标函数就不单单只有车辆总行驶距离了,还要包括当前解中 ...
- 【背包问题】基于matlab禁忌搜索算法求解背包问题【含Matlab源码 373期】
一.获取代码方式 获取代码方式1: 完整代码已上传我的资源:[背包问题]基于matlab禁忌搜索算法求解背包问题[含Matlab源码 373期] 获取代码方式2: 通过订阅紫极神光博客付费专栏,凭支付 ...
最新文章
- java录排名怎么写_面试官:Java排名靠前的工具类你都用过哪些?
- 下载 NCBI sra 文件
- 【动态规划】炮兵阵地
- ansible高级应用示例
- 一篇文章弄懂Java反射基础和反射的应用场景
- Ubuntu 安装 redmine
- springboot2 虚拟路径设置_转载—springboot配置虚拟路径以外部访问
- Android Studio创建签名文件,打包apk,多渠道打包
- mysqlinsert触发器的创建
- 基于JAVA便利店库存管理计算机毕业设计源码+系统+lw文档+部署
- Ubuntu下好用的文档比较工具Meld,代替Notepad++的文档对比功能?
- win7和win10对于wifi共享的不同
- 数据可视化之热力图相关系数图(原理+Python代码)
- 只道情深,奈何缘浅!
- 计算机如何连接wifi台式,台式电脑怎么连wifi
- 爱就是当你坐在他身边,哪怕什么都不做,也会感觉很开心
- 图片无损压缩(ubuntu 安装 )
- DirectX 11 编程指南
- 嵌入式 -固件防复制系列【1】GD32代码读保护
- 【HTML+CSS(六)】
热门文章
- visual studio 2013 编译 filezilla和filezilla server
- html元素 按键精灵鼠标移动,按键精灵后台鼠标移动和点击脚本怎么制作。
- html保护眼睛背景色,保护眼睛的颜色和各种背景颜色设置方法
- 金三银四,冰河为你整理了这份20万字134页的面试圣经!!
- 02-即时通讯-XMPP 简单介绍
- Linux下rpm包x86、i386、i486、i586、i686和x86_64这些后缀含义
- 2.10 数值分析: 条件数的定义及计算
- 苹果电脑怎么安装计算机一级,苹果系统安装教程,详细教您苹果电脑怎么重装系统...
- Gitlab-IDEA使用教程
- 软件测试性能测试报告完整版,性能测试报告模板