问题描述
我正在尝试使用回溯对 TSP 问题的递归实现进行编码。
尝试了几次,但我刚刚完成,它似乎有效。
但是它有点慢,所以我想弄清楚如何改进它。
def search_best_route(distance_matrix):
best_route = [None] * (len(distance_matrix[0]))
route = best_route.copy()
visited = [False] * (len(distance_matrix[0]))
current_distance = 0
return search_routes(0,route,best_route,-1,current_distance,distance_matrix,visited,0)
def search_routes(start_index1,min_distance,best_distance,last_visited):
if start_index1 == len(route):
current_distance += distance_matrix[last_visited][0]
if current_distance < best_distance or best_distance == -1:
best_distance = current_distance
for k in range(0,len(route)):
best_route[k] = route[k]
else:
for k in range(len(route)):
if not visited[k]:
new_min = min_distance - distance_matrix[last_visited][k]
if new_min < best_distance or start_index1 == 0:
new_current_distance = current_distance + distance_matrix[last_visited][k]
route[start_index1] = k
visited[k] = True
best_distance = search_routes(start_index1 + 1,new_min,new_current_distance,k)[1]
visited[k] = False
return best_route,best_distance
def build_distance_matrix(x,y):
distance_matrix = [[0 for col in range(len(x))] for row in range(len(x))]
for i in range(len(x)):
for j in range(len(x)):
distance_matrix[i][j] = ((x[i] - x[j]) ** 2 + (y[i] - y[j]) ** 2) ** 0.5
return distance_matrix
n = int(input())
x = [None] * n
y = x.copy()
for i in range(n):
x_y = input()
x[i] = x_y.split()[0]
y[i] = x_y.split()[1]
x = list(map(float,x))
y = list(map(float,y))
best_route = search_best_route(build_distance_matrix(x,y))
print("%.4f" % best_route[1])
print(' '.join(map(str,best_route[0])))
对不起,如果我做错了什么,你在看这个哈哈。
解决方法
一个可能会有帮助的小改动是,您在每一步都遍历整个路线列表。您可以通过维护一个尚未访问的点的列表来节省 n 的因数,递归排列枚举算法就是这样做的。
在纸面上,n 的因数可能看起来很多,但由于算法仍然是 Θ(n!),因此在相同的运行时间内提高了一个点。为了做得更好,您需要实现分支定界。
基本的分支定界并不难实现,因为递归回溯已经是“分支”部分的大部分工作。最简单的边界策略是检查到目前为止的距离是否超过当前的最小值,如果是,则拒绝探索分支。如果您首先探索最有希望的分支(例如,通过增加与当前点的距离对候选下一个点进行排序),这会更有效。
复杂性的一步是使用 1-tree bound。给定一些点上的路径,我们想估计将其扩展到旅行而不走过去的成本。每个这样的扩展都包含从给定路径中的最后一个点到某个未访问点的边、所有未访问点上的路径以及从某个未访问点返回到给定路径中的第一个点的边。在未访问点上获得路径的最小成本是很困难的——这基本上是 TSP。然而,我们可以通过计算这些点上最小生成树的成本来降低它,因为路径是生成树。我们的最终估计是
- 当前路径的成本,
- 从当前路径中的第一个点到最近的未访问点的距离,
- 从当前路径中的最后一个点到最近的未访问点的距离,
- 未访问点上最小生成树的成本。
从那里开始,根据您对数学的熟练程度,有大量关于精确 TSP 算法改进的文献。