【问题标题】:Using A* to solve Travelling Salesman使用 A* 解决旅行推销员
【发布时间】:2011-05-26 02:32:21
【问题描述】:

我的任务是编写 A* 算法(提供启发式算法)的实现,以解决旅行商问题。我了解算法,它很简单,但我看不到实现它的代码。我的意思是,我明白了。节点的优先级队列,按距离 + 启发式(节点)排序,将最近的节点添加到路径上。问题是,如果不能从前一个最近的节点到达最近的节点会发生什么?一个人实际上如何将“图形”作为函数参数?我只是看不到算法实际上是如何工作的,就像代码一样。

我在发布问题之前阅读了维基百科页面。反复。它并没有真正回答这个问题——搜索图表是一种方式,与解决 TSP 方式不同。例如,您可以构建一个图,其中任何给定时间的最短节点总是导致回溯,因为两条相同长度的路径不相等,而如果您只是尝试从 A 到 B,那么两条路径相同的长度是相等的。

您可以得出一个图,通过始终先走最近的方式永远无法到达某些节点。

我真的不明白 A* 如何适用于 TSP。我的意思是,找到从 A 到 B 的路线,当然,我明白了。但是TSP?我没有看到连接。

【问题讨论】:

  • A* 似乎是我从 CS 课程中记得的一个很好的总结。 Dijkstra algorithm 非常相似(但更简单),因此开始时可能会更好。优先级队列在这两种情况下都很方便。
  • @pst:如果你想从 A 点到 B 点,A* 和 Dijkstra 的算法很有用。如果你想通过具有特定约束的路径从 A 点到 A 点,那么,那是另一回事。
  • 当我在 Uni 的时候(上个千年),我们有一个任务是用我们想要的任何语言实现 A*,大多数人选择了我们最熟悉的 C++,但我选择了 Prolog,因为它看起来更适合这个问题。长话短说,我完成任务的速度比大多数人都快,你也许可以从 Prolog 开始,跳过中间阶段。
  • “[...] 或特定于语言的代码,例如 Boost。” Boost::graph 有一个 A* 的实现
  • 作为副本被关闭的......

标签: algorithm a-star traveling-salesman


【解决方案1】:

我找到了解决方案here

使用最小生成树作为启发式。

设置 初始状态:代理在起始城市且未访问过任何其他城市

目标状态:代理已访问所有城市并再次到达起始城市

后继功能:生成所有尚未访问过的城市

Edge-cost:节点所代表的城市之间的距离,用这个成本计算g(n)。

h(n):从当前城市到最近的未访问城市的距离 + 估计旅行所有未访问城市的距离(此处使用 MST 启发式)+ 从未访问城市到起始城市的最近距离。请注意,这是一个可接受的启发式函数。 您可以考虑维护访问城市列表和未访问城市列表以方便计算。

【讨论】:

  • 可以在 MST 的行为违反直觉的情况下构建有问题的图表。假设您有一张图表,其中有 N 个城市可供访问。使用 MST,您可以获得到目标的剩余距离的下限。然后删除一个城市,留下N-1个城市去访问。现在到目标的剩余距离可能更大!本周这个问题困扰着我,因为我试图在我的 A* 最近邻搜索中使用最小生成树。我的解决方案是减去一个奖金乘以访问的城市数量来平滑函数。
  • 这种启发式甚至不可接受。由于在构建 MST 时删除了一些边,因此 MST 中两个城市之间的距离可能大于实际图中两个城市之间的距离。
【解决方案2】:

这里的困惑在于,您尝试求解 TSP 的图不是您正在执行 A* 搜索的图。

查看相关:Sudoku solving algorithm C++

要解决这个问题,你需要:

  • 定义您的:
    • TSP 状态
    • TSP 初始状态
    • TSP 目标状态
    • TSP 状态后继函数
    • TSP 状态启发式
  • 将通用 A* 求解器应用于此 TSP 状态图

一个我能想到的简单例子:

  • TSP 状态:当前处于 TSP 周期的节点(城市)列表
  • TSP 初始状态:包含单个节点的列表,即旅行商的家乡
  • TSP 目标状态:如果一个状态包含城市图中的每个节点,那么它就是一个目标
  • TSP后继功能:可以将任何不在当前循环中的节点(城市)添加到循环中的节点列表的末尾以获得新的状态
    • 过渡的成本等于您添加到循环中的边的成本
  • TSP 状态启发式:由您决定

【讨论】:

    【解决方案3】:

    如果只是理解算法及其工作原理的问题,您可能需要考虑在纸上绘制图表,为其分配权重并将其绘制出来。您还可以找到一些显示 Dijkstra 最短路径的动画,Wikipedia 有一个很好的。 Dijkstra 和 A* 之间的唯一区别是添加了启发式算法,一旦到达目标节点就停止搜索。至于用它来解决 TSP,祝你好运!

    【讨论】:

    • 如果暗示用 A* 求解 TSP 将很困难,那么它不是。我同意上面的评论,从 Dijkstra 开始可能会更容易,但是一旦你决定了实现细节,两者都非常简单。
    • 我想我没有看到 A* 如何帮助您解决 TSP。通过只允许选择最近的未访问邻居,您将获得一条有效的路线,但不一定是最短的路线。 TSP(正如它一直对我所说的那样)想要最短的非重复路径。也许我误解了 OP 的目标。
    【解决方案4】:

    更抽象地考虑一下这个问题。暂时忘掉A*吧,无论如何它只是带有启发式的dijkstra。以前,你想从 A 到 B。你的目标是什么?到达 B。目标是以最少的成本到达 B。在任何给定的时间点,您当前的“状态”是什么?可能只是您在图表上的位置。

    现在,你想从 A 开始,然后去 B 和 C。你现在的目标是什么?通过 B 和 C,保持最低成本。您可以使用更多节点来概括这一点:D、E、F、...或仅 N 个节点。现在,在任何给定的点上,您当前的“状态”是什么?这很关键:它不仅仅是您在图表中的位置 - 它也是 B 或 C 中的哪一个或您迄今为止在搜索中访问过的任何节点。

    实现您的原始算法,以便在 X 移动后调用一些函数来询问它是否已达到“目标状态”。之前,该函数只会说“是的,您处于状态 B,因此您处于目标位置”。但是现在,如果搜索的路径已经经过每个兴趣点,让该函数返回“是的,您处于目标状态”。它会知道搜索是否已通过所有兴趣点,因为它包含在当前状态中。

    得到这些之后,用一些启发式方法改进搜索,然后 A* 优化它。

    【讨论】:

    • 我很难理解 dijekstrs 但你的想法看起来很暴力。
    【解决方案5】:

    回答您的一个问题...

    要将图形作为函数参数传递,您有多种选择。您可以将指针传递给包含所有节点的数组。如果它是一个完全连接的图,您可以只传递一个起始节点并从那里开始工作。最后,您可以编写一个图形类,其中包含您需要的任何数据结构,并将引用传递给该类的实例。

    至于您关于最近节点的其他问题,A* 搜索的一部分是否会根据需要回溯?或者您可以实施自己的回溯来处理这种情况。

    【讨论】:

      【解决方案6】:

      问题是,如果不能从上一个最近的节点到达最近的节点会发生什么?

      这一步不是必须的。例如,您不是在计算从上一个最近到当前最近的路径,而是在尝试到达目标节点,而当前最接近的是唯一重要的事情(例如,算法不关心最后一次迭代你在 100 公里之外,因为这次迭代你只有 96 公里)。

      作为广义的介绍,A* 并不直接构建路径:它会进行探索,直到明确知道路径包含在它所探索的区域内,然后根据探索过程中记录的信息构建路径。

      (我将使用the code in the Wikipedia article 作为参考实现来帮助我解释。)

      您有两组节点:closedsetopenset

      closedset 包含已完全评估的节点,也就是说,您确切知道它们与start 的距离以及它们的所有邻居都在两组之一中。这没有更多的计算你可以用它们做,所以我们可以(有点)忽略它们。 (基本上这些都完全包含在边界内。)

      openset 拥有“边界”节点,您知道这些与start 的距离有多远,但您还没有接触到它们的邻居,所以它们目前处于您搜索的边缘。

      (隐含地,还有第三组:完全未触及的节点。但直到它们在 openset 中才真正触及它们,所以它们无关紧要。)

      在给定的迭代中,如果您有要探索的节点(即openset 中的节点),您需要确定要探索的节点。这是启发式算法的工作,它通过告诉你它认为哪个节点将具有到goal 的最短路径,基本上给你一个提示,告诉你边界上的哪个点是下一个最好探索的点。

      之前最近的节点无关紧要,只是稍微扩大了边界,在openset添加了新节点。这些新节点现在是本次迭代中最近节点的候选者。

      起初,openset 仅包含 start,但随后您进行迭代,并在每一步中将边框扩大一点(朝最有希望的方向),直到最终到达 goal

      当 A* 实际进行探索时,它并不担心哪些节点来自哪里。它不需要,因为它知道它们与start 的距离以及启发式函数,这就是它所需要的全部。

      但是以后要重构路径,你需要有一些路径的记录,这就是camefrom。对于给定节点,camefrom 将其链接到最接近start 的节点,因此您可以通过从goal 向后跟踪链接来重建最短路径。

      实际上如何将“图形”作为函数参数?

      通过传递representations of a graph 之一。

      我真的不明白 A* 如何适用于 TSP。我的意思是,找到从 A 到 B 的路线,当然,我明白了。但是TSP?我没有看到连接。

      您需要不同的启发式和不同的结束条件:goal 不再是单个节点,而是所有连接的状态;并且您的启发式是对连接其余节点的最短路径长度的一些估计。

      【讨论】:

        猜你喜欢
        • 2019-09-04
        • 1970-01-01
        • 2015-09-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-22
        • 2011-09-08
        • 2015-04-28
        相关资源
        最近更新 更多