我在发布问题之前多次阅读了维基百科页面。它并没有真正回答这个问题——搜索图形与解决TSP完全不同。例如,可以构造一个图形,其中任何时候最短节点都会导致回溯,因为两条相同长度的路径并不相等,而如果你只是想从A到B,则两条相同长度的路径是相等的。
您可以通过始终选择最接近的节点来派生图形,其中某些节点永远不会到达。
我确实看不出A*算法如何应用于TSP。我的意思是,从A到B找到路线,当然可以。但是TSP呢?我看不出二者之间的联系。
我在这里找到了解决方案。
使用最小生成树作为启发式。
设置 初始状态:代理在起始城市并且没有访问过其他任何城市
目标状态:代理已经访问了所有城市并回到了起始城市
后继函数:生成尚未访问的所有城市
边缘成本:节点表示的城市之间的距离,使用该成本计算g(n)。
h(n):从当前城市到最近未访问城市的距离+预计通过所有未访问城市的距离(这里使用MST启发式)+最近未访问城市到起始城市的距离。请注意,这是一种可接受的启发式函数。 您可以考虑维护已访问城市列表和未访问城市列表以便于计算。
抽象地思考一下。暂时忘记A*算法,它只是带有启发式的Dijkstra算法而已。之前,你想从A到B。你的目标是什么?是到达B。目标是以最小代价到达B。在任何给定的时刻,你的当前“状态”是什么?可能只是你在图上的位置。
现在,你想从A开始,然后去B和C。你现在的目标是什么?是经过B和C,保持最小代价。你可以通过更多节点来概括这个问题:D、E、F...或者N个节点。现在,在任何给定的时刻,你的当前“状态”是什么?这很关键:它不仅仅是你在图中的位置——还包括你在搜索中已经访问过哪些节点,比如B或C或其他节点。
实现您的原始算法,使其调用某些函数询问是否在进行X次移动后已达到“目标状态”。在此之前,该函数只会说“是的,您处于B状态,因此您已经到达了目标”。但现在,让该函数返回“是的,您已经到达了目标状态”,如果搜索路径已经经过了所有感兴趣的点。它将知道搜索是否已经经过了所有感兴趣的点,因为这包含在当前状态中。
在完成上述步骤后,使用一些启发式方法来改进搜索,并进行A*优化。
回答你的一个问题...
要将图形作为函数参数传递,您有几个选项。您可以传递指向包含所有节点的数组的指针。如果它是完全连接的图,则可以仅传递一个起始节点并从那里开始工作。最后,您可以编写一个带有所需数据结构的图形类,并传递对该类实例的引用。
至于您关于最接近节点的另一个问题,A*搜索的一部分不是会根据需要进行回溯吗?或者您可以实现自己的回溯方式来处理这种情况。
closedset
和openset
closedset
存储已经完全评估过的节点,也就是说,你已经知道它们离 start
的距离以及它们所有邻居节点所在的集合。因此,你无法再进行更多的计算,可以(某种程度上)忽略它们。(基本上,这些节点完全包含在边界内部。)
openset
存储“边缘”节点,即你已经知道它们离start
有多远,但是它们的邻居节点还没有被访问,因此它们是目前搜索的边缘。
(隐含地,存在第三个集合:完全未访问的节点。但是直到它们进入 openset
才会真正访问它们,因此它们并不重要。)
在给定的迭代中,如果你有要探索的节点(即在 openset
中的节点),则需要确定要探索哪个节点。这是启发式算法的工作,它基本上会提示你关于边界上最佳探索点的信息,并告诉你认为哪个节点将具有到 goal
的最短路径。
之前最接近的节点并不重要,它只是稍微扩展了边界,向openset
添加了新节点。这些新节点现在成为本次迭代中最接近节点的候选。
起初,openset
只包含start
,但随后您会进行迭代,在每个步骤中,边界会稍微扩展一点(在最有希望的方向上),直到最终到达goal
。
当A*实际进行探索时,它不需要担心哪些节点来自哪里。它不需要,因为它知道它们距离start
的距离和启发式函数,这就是它所需要的全部。
然而,为了以后重构路径,您需要记录一些路径信息,这就是camefrom
的作用。对于给定的节点,camefrom
将其链接到最靠近start
的节点,因此您可以通过从goal
反向跟随链接来重构最短路径。
通过传递图的表示方式之一。如何将“图形”作为函数参数?
我真的不明白A*算法如何应用于TSP问题。我的意思是,从A到B找到一条路线,当然,我明白这一点。但是TSP问题呢?我看不出两者之间的联系。
你需要一个不同的启发式和不同的结束条件:goal
不再是单个节点,而是所有节点都连接的状态;你的启发式是连接剩余节点的最短路径长度的估计值。