回溯法按深度优先策略搜索问题的解空间树。首先从根节点出发搜索解空间树,当算法搜索至解空间树的某一节点时,先利用剪枝函数判断该节点是否可行(即能得到问题的解)。如果不可行,则跳过对该节点为根的子树的搜索,逐层向其祖先节点回溯;否则,进入该子树,继续按深度优先策略搜索。
回溯法的基本行为是搜索,搜索过程使用剪枝函数来为了避免无效的搜索。剪枝函数包括两类:1. 使用约束函数,剪去不满足约束条件的路径;2.使用限界函数,剪去不能得到最优解的路径。
问题的关键在于如何定义问题的解空间,转化成树(即解空间树)。解空间树分为两种:子集树和排列树。两种在算法结构和思路上大体相同。
一、问题描述
假设有一个旅行商人要拜访 个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是使求得的路径长度为所有路径之中的最小值。
例如,现在有4个城市,其各顶点的路径长度如下所示:
二、问题分析
旅行售货员问题(TSP问题)是一个经典的组合优化问题。经典TSP问题可以描述为:一个商品推销员要去若干个城市推销商品,该推销员从一个城市出发,需要经过所有城市后,回到出发地。应如何选择行进路线,以使总的行程最短。
从图论角度看:
该问题实质是在一个带权完全无向图中,找一个权值最小的Hamilton回路。由于该问题的可行解是所有顶点的全排列,随着顶点数的增加,会产生组合爆炸,它是一个NP完全问题。
TSP的数学模型为:
三、实验代码
# 回溯法求解旅行商问题
import math
n = 4
x = [0, 1, 2, 3]
# 定义图的字典形式
G = {
'1': {'2': 3, '3': 6, '4': 7},
'2': {'1': 5, '3': 2, '4': 3},
'3': {'1': 6, '2': 4, '4': 2},
'4': {'1': 3, '2': 7, '3': 5}
}
# 定义图的数组形式
graph = [
[0, 3, 6, 7],
[5, 0, 2, 3],
[6, 4, 0, 2],
[3, 7, 5, 0]
]
# bestcost = 1<<32 # 这里只要是一个很大数就行了 无穷其实也可以
bestcost = math.inf # 直接取无穷好了
nowcost = 0 # 全局变量,现在的花费
def TSP(graph, n, s):
global nowcost, bestcost
if (s == n):
if (graph[x[n - 1]][x[0]] != 0 and (nowcost + graph[x[n - 1]][x[0]] < bestcost)):
print('best way:', x)
bestcost = nowcost + graph[x[n - 1]][x[0]]
print('bestcost', bestcost)
else:
for i in range(s, n):
# 如果下一节点不是自身 而且 求得的值小于目前的最佳值
if (graph[x[i - 1]][x[i]] != 0 and nowcost + graph[x[i - 1]][x[i]] < bestcost):
x[i], x[s] = x[s], x[i] # 交换一下
nowcost += graph[x[s - 1]][x[s]] # 将花费加入
TSP(graph, n, s + 1)
nowcost -= graph[x[s - 1]][x[s]] # 回溯上去还需要减去
x[i], x[s] = x[s], x[i] # 别忘记交换回来
TSP(graph, n, 1)
四、实验结果
D:\Miniconda3\python.exe D:/算法分析与设计/实验/实验三/回溯法—旅行售货员问题.py
best way: [0, 1, 2, 3]
bestcost 10
Process finished with exit code 0