一、禁忌搜索算法
采用邻域选优的搜索方法,为了逃离局部最优解,算法必须能够接受劣解,也就是每一次得到的解不一定优于原来的解。但是,一旦接受了劣解,算法迭代即可能陷入循环。为了避免循环,算法将最近接受的一些移动放在禁忌表中,在以后的迭代中加以禁止。即只有不再禁忌表中的较好解(可能比当前解差)才能接受作为下一代迭代的初始解。随着迭代的进行,禁忌表不断更新,经过一定的迭代次数后,最早进入禁忌表的移动就从禁忌表中解禁退出。
二、Python实现
import matplotlib.pyplot as plt
import random
import time
Fee_data = [[0,382,352,800,666],
[382,0,892,158,235],
[253,780,0,678,111],
[862,123,768,0,255],
[666,1080,123,255,0]]
city_count = len(Fee_data[0]) # 城市数
origin = 1 # 起点、终点城市
remain_cities = [i for i in range(city_count)]
remain_cities.remove(origin) # 迭代过程中变动的城市
remian_count = city_count - 1
def route_mile_cost(route):
"""
:param route:运行路线
"""
mile_cost = 0.0
mile_cost += Fee_data[origin-1][route[0]-1]
for i in range(remian_count-1):
mile_cost += Fee_data[route[i]-1][route[i+1]-1]
mile_cost += Fee_data[route[-1]-1][origin-1]
return mile_cost
def random_initial_route(remain_cities):
"""
随机生成初始路径
"""
initial_route = remain_cities[:]
random.shuffle(initial_route)
mile_cost = route_mile_cost
return initial_route,mile_cost
improve_count = 20 # 改良次数
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 = 0
while 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-cost0
if improve < 0:
route = new_route[:]
cost0 = cost1
j += 1
else:
continue
initial_route = route[1:-1]
return initial_route,cost0
def nearest_city(current_city,cand_cities):
"""
找寻当前城市最近的城市
"""
temp_min = float("inf")
next_city = None
for i in range(len(cand_cities)):
distance = Fee_data[current_city-1][cand_cities[i]-1]
if distance < temp_min:
temp_min = distance
next_city = cand_cities[i]
return next_city,temp_min
def greedy_initial_route(remain_cities):
"""
贪婪算法,每次寻找最近的城市
"""
cand_cities = remain_cities[:]
current_city = origin
mile_cost = 0
initial_route = []
# print(cand_cities,"cand_cities")
while len(cand_cities) > 0:
# 找到最近的城市
next_city,distance = nearest_city(current_city,cand_cities)
mile_cost += distance
# 将下一个城市放入路径列表中
initial_route.append(next_city)
# 更新当前城市
current_city = next_city
# 更新未定序城市
cand_cities.remove(next_city)
# 回到起点
mile_cost += Fee_data[initial_route[-1]-1][0]
return initial_route,mile_cost
candidate_routes_size = 5
tabu_size = 10
tabu_list = [] #禁忌表
def random_swap_2_city(route):
new_route = route[:]
swap_2_city = random.sample(route,2)
index = [0]*2
index[0] = route.index(swap_2_city[0])
index[1] = route.index(swap_2_city[1])
index = sorted(index)
L = index[1] - index[0] + 1
for j in range(L):
new_route[index[0]+j] = route[index[1]-j]
return new_route,sorted(swap_2_city)
def generate_new_route(route):
"""
生成新路线
"""
global tabu_list,best_so_far_cost,best_so_far_route
global candidate_routes,tabu_size
candidate_routes = [] # 路线候选集合
candidate_mile_cost = [] # 候选集合路线对应的费用
candidate_swap = [] # 交换元素
while len(candidate_routes) < candidate_routes_size:
cand_route,cand_swap = random_swap_2_city(route)
print("*******************")
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)
print(i,"i")
# 如果这次交换集的最优值比历史最优值要好,则更新历史最优值和最优路线
if min_mile_cost < best_so_far_cost:
print("88888888")
best_so_far_cost = min_mile_cost
best_so_far_route = candidate_routes[i]
print(best_so_far_route,"best_so_far_route")
print(new_route,"new_route")
new_route = candidate_routes[i]
if candidate_swap[i] in tabu_list:
print("))))))))))))))))藐视法则")
tabu_list.remove(candidate_swap[i]) # 藐视法则
elif len(tabu_list) >= tabu_size:
print("2222222222222222222222")
tabu_list.remove(tabu_list[0])
tabu_list.append(candidate_swap[i])
else:
print(":::::::::")
# 此次交换集未找到更优的路径,则选择交换方式未在禁忌表中的次优
K = candidate_routes_size
stop_value = K - len(tabu_list) - 1
while K > stop_value:
print(candidate_routes,"candidate_routes")
min_mile_cost = min(candidate_mile_cost)
i = candidate_mile_cost.index(min_mile_cost)
# 如果这次的交换集的最优值比历史最优值更好,则更新历史最优解和最优路线
if min_mile_cost < best_so_far_cost:
print("[[[[[[[[[[[]]]]]]]]]]]")
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:
print("3333333333333333333333")
tabu_list.remove(candidate_swap[i]) #藐视法则
elif len(tabu_list) >= tabu_size:
print("444444444444444444444")
tabu_list.remove(tabu_list[0])
tabu_list.append(candidate_swap[i])
break
else:
print("line175-----------")
# 此次交换集未找到更优路径,则选择交换方式未在禁忌表中的次优
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:
print("55555555555555555555")
tabu_list.remove(tabu_list[0])
break
else:
print("66666666666666666666666666")
candidate_mile_cost.remove(min_mile_cost)
candidate_swap.remove(candidate_swap[i])
candidate_routes.remove(candidate_routes[i])
K -= 1
print(new_route,"new==========")
return new_route,best_so_far_cost
def tabu_search(remain_cities,iteration_count = 10):
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)
print("*******初始解生成完成********")
print(best_so_far_route,"初始解")
print(best_so_far_cost,"初始费用")
new_route = best_so_far_route[:]
print(new_route,"new_route")
# 生成邻域空间
# j = 0
record = [best_so_far_cost]
for j in range(iteration_count):
# print(j,"j")
new_route = generate_new_route(new_route)
record.append(best_so_far_cost)
# j += 1
print(record,"record")
# 输出最后搜索结果
final_route = [origin] + best_so_far_route + [origin]
return final_route,best_so_far_cost,record
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 = [i for i in range(N+1)]
Y = record[:]
plt.xlabel("迭代次数",fontproperties = "SimSun")
plt.ylabel("路径费用",fontproperties = "SimSun")
plt.title("禁忌搜索法")
plt.plot(X,Y,"-")
plt.show()
if __name__ == "__main__":
main()