Algorithm 计算从开始到结束访问特定节点的最短路径

Algorithm 计算从开始到结束访问特定节点的最短路径,algorithm,graph,graph-algorithm,shortest-path,Algorithm,Graph,Graph Algorithm,Shortest Path,我有以下图表: 图形包含n节点(p1、p2、…、pn) 每个节点都以正成本数连接到其他节点。不存在的连接标记为无穷成本编号 图是无向的(对于任何节点对,(pi,pj)的代价等于(pj,pi)的代价) 图表可能包含循环,例如,可能存在从pi节点返回到该节点的路径 我需要计算从p1到pn节点访问pk节点的最短路径(pk不是开始或结束节点)。主要问题在于解决方案路径不应访问任何节点超过一次。因此,可能根本没有解决方案:例如,当节点pk只有一个非无限连接时(使用pj节点),路径将必须通过pj节点两次

我有以下图表:

  • 图形包含n节点(p1、p2、…、pn)
  • 每个节点都以正成本数连接到其他节点。不存在的连接标记为无穷成本编号
  • 图是无向的(对于任何节点对,(pi,pj)的代价等于(pj,pi)的代价)
  • 图表可能包含循环,例如,可能存在从pi节点返回到该节点的路径
我需要计算从p1到pn节点访问pk节点的最短路径(pk不是开始或结束节点)。主要问题在于解决方案路径不应访问任何节点超过一次。因此,可能根本没有解决方案:例如,当节点pk只有一个非无限连接时(使用pj节点),路径将必须通过pj节点两次


有什么可以接受的算法来解决这个问题吗?

我将建议对受其启发的Winata算法进行修改-除了简单的情况外,它并不伟大,但我开始怀疑这是一个困难的问题

Winata建议我们计算从p1和pn到pk的最短路径,并通过pk合并这些路径以获得从p1到pn的路径。如果返回的答案满足额外的约束,即没有节点被多次访问,那么问题就解决了。问题是,这里找到的解决方案可能不满足该约束

我建议我们希望Winata答案与正确答案没有太大区别,并开始列举从p1到pk以及从pk到pn的所有最短路径。给定这些枚举,我们可以按顺序枚举从p1到pk和pk到pn的所有路径组合,并查找满足额外约束的第一个路径,该路径必须是此类路径的最短路径

本文描述了一种计算问题解的通用方法(Lawler-Murty),给出了一种只求问题一个最优解的方法。例如,在附录A第9页中,它解决了按长度顺序通过图形生成从源到目标的路径的问题

这种方法的一个缺陷是枚举方法需要越来越多的存储来跟踪问题的简化版本。另一种方法是使用Winata的方法——它解决了一个忽略问题约束的简单问题——在分支定界方法中提供下限。Winata方法提供的解决方案可能无效,但其成本是任何有效解决方案成本的下限,这正是分支和绑定所需的

我怀疑分支定界实际上是一个更好的解决方案,所以我将尝试更全面地解释这一点。有一个分支和边界的一般描述。它是一种递归搜索,非常类似于深度优先搜索,其中每个节点对应于问题的部分解决方案。在这里,一个局部的解决方案是一个提议的路径中心部分,几个链接通向pk,几个链接远离pk。在对部分解树进行深度优先搜索时,您可以跟踪到目前为止找到的最佳解。当你递归到某个节点时,你会尝试证明该节点下的完整解不会比目前为止找到的最佳解更好,因为如果是这样,你不需要进一步研究通过扩展该部分解而形成的任何解,您可以返回到深度优先搜索,而不是在该节点下递归

当你有一个部分解,比如(Pk-1,Pk,Pk+1),你可以算出从P1到Pk-1和从Pk+1到Pn的最短路径。这可能不合法,但它仍然是一个下限-没有任何以(Pk-1,Pk,Pk+1)为中心部分的合法解决方案可能比您计算出的路径总数做得更好。因此,如果这个总和不比目前为止找到的最佳解好,你就不需要进一步扩展这个部分解来研究任何其他的部分解。如果三个部分的组合是一个合法的解决方案,访问每个节点不超过一次,那么您已经找到了一个可能的答案,并且再次不需要调查树中此节点下方的任何节点。如果结果不是合法的路径,那么您必须尝试扩展部分解决方案,方法是以各种可能的合法方式在部分解决方案的前面(或末尾)添加链接,递归地在树的下面查找部分解决方案

如果根本没有解决方案,您应该发现深度优先搜索总是终止,无法在某个深度扩展每个部分解决方案,也无法找到完整的法律路径。如果有解决方案,而且你很幸运,你会很快找到一条成本很低的法律途径,你可以证明没有任何其他部分解决方案可以超越它。-但无法保证该过程可能需要多长时间——对于困难的问题,它可能需要太长时间才能实用。

另一种解决方案:

由于这是一个无向图,解决方案并不困难,即:

  • 在执行以下操作时,通过另一个名为
    pathTo
    的数组跟踪每个节点的父节点,该数组将包含
    PT(k,p)
    ,其中
    k
    是当前节点,沿最短路径连接到它的父节点是
    p

  • 首先运行dijkstra算法,获得从
    p1
    到连接到
    pk
    的所有点的最短路径。因此,如果
    pk
    有两条边,您需要运行此算法,直到这些边被放松

  • 接下来,使用宽度优先搜索查找从连接到
    pk
    的任何顶点到
    pn
    的最短路径。这意味着您将把所有
    pk
    有边的顶点作为bfs的起点