参考资料
变邻域搜索算法(VNS)迅速掌握
TSP问题–变邻域搜索(VNS)算法
搬运工。
import numpy as np
import random as re
import math
import copy
from multiprocessing import Pool as ThreadPool
import time
def read_data():
f = open('att48.tsp/att48.txt', encoding='gbk')
lines = f.readlines()
count = 0
cus_lon = []
for line in lines:
count += 1
if count >= 7:
str_ = line.strip().split()
if str_[0] == 'EOF':
break
currentSolution.append(int(str_[0])-1)
cus_lon.append([int(str_[1]), int(str_[2])])
cus_lon = np.array(cus_lon)
# 计算两点间的距离
get_distance(cus_lon)
# 计算两点间距离
def get_distance(cus_lon):
for i in range(len(cus_lon)):
temp = cus_lon[i]
# 伪欧氏距离在根号内除以了一个10
dis_ = (((temp[0] - cus_lon[:, 0]) ** 2 + (temp[1] - cus_lon[:, 1]) ** 2) / 10)**0.5
# dis_ = ((temp[0] - cus_lon[:, 0]) ** 2 + (temp[1] - cus_lon[:, 1]) ** 2)**0.5
distMat.append(list(dis_))
def disCal(path):
# global distMat
dis = 0
for i in range(len(path) - 1):
dis += distMat[path[i]][path[i + 1]]
dis += distMat[path[0]][path[-1]]
return dis
# 抖动:将城市分成4块,扰动再组合
def sharking(solution):
solution_ = []
city_ = math.ceil(len(solution) / 4)
for i in range(4):
solution_.append(solution[i*city_:(i+1)*city_])
sequence = [i for i in range(4)]
re.shuffle(sequence)
solution = []
for se in sequence:
solution += solution_[se]
return solution
def variableNeighborhoodDescent(solution):
i = 0
dis, k = float('inf'), -1
# 进行邻域搜索动作
while i < 3:
if i == 0:
neiborSolution = neighborhoodOne(solution)
elif i == 1:
neiborSolution = neighborhoodTwo(solution)
elif i == 2:
neiborSolution = neighborhoodThree(solution)
# 遍历找到的所有邻域,判断与当前解进行比较
for j in range(len(neiborSolution)):
if disCal(neiborSolution[j]) < dis:
dis = disCal(neiborSolution[j])
k = j
# 多线程
# pool_ = ThreadPool(7)
# opt_val = pool_.map(disCal, neiborSolution)
# pool_.close() # 关闭进程池
# pool_.join()
# temp = min(opt_val)
# if temp < dis:
# dis = temp
# k = opt_val.index(temp)
if dis < disCal(solution):
# 重新回到第一种邻域
solution = neiborSolution[k]
i = 0
else:
i += 1
return disCal(solution), solution
# 邻域动作:两点互换(swap)
def neighborhoodOne(sol):
neighbor = []
for i in range(len(sol)):
for j in range(i + 1, len(sol)):
s = copy.deepcopy(sol)
x = s[j]
s[j] = s[i]
s[i] = x
neighbor.append(s)
return neighbor
# 邻域动作:两点间反转(two_opt_swap)
def neighborhoodTwo(sol):
neighbor = []
for i in range(len(sol)):
for j in range(i + 3, len(sol)): # 这里j从i+3开始是为了不产生跟swap算子重复的解
s = copy.deepcopy(sol)
s1 = s[i:j+1]
s1.reverse()
s = s[:i] + s1 + s[j+1:]
neighbor.append(s)
return neighbor
# 邻域动作:two_h_opt_swap算子
def neighborhoodThree(sol):
neighbor = []
for i in range(len(sol)):
for j in range(i+1, len(sol)):
s = copy.deepcopy(sol)
s = [s[i]] + [s[j]] + s[:i] + s[i+1:j] + s[j+1:]
neighbor.append(s)
return neighbor
currentSolution = []
distMat = []
city_size = len(currentSolution)
# 读取数据
read_data()
if __name__ == '__main__':
st = time.time()
# 参数定义
# 随机产生初始解,当前解成本
distMat = np.array(distMat)
re.shuffle(currentSolution)
shorterDistance = disCal(currentSolution)
iterx, iterxMax = 0, 10
while iterx < iterxMax:
print(shorterDistance, " : ", currentSolution)
# 抖动
currentSolution = sharking(currentSolution)
# VND
currentDistance, currentSolution = variableNeighborhoodDescent(currentSolution)
if currentDistance < shorterDistance:
shorterDistance = currentDistance
itrex = 0
else:
iterx += 1
print(currentSolution)
print(shorterDistance)
print(time.time() - st)
测试数据来源:att48.tsp.gz
不知道为啥开了多线程反而更慢了。
仅供学习,侵权删。