【问题标题】:A* find the second shortest pathA* 找到第二条最短路径
【发布时间】:2014-05-13 05:20:34
【问题描述】:

我正在尝试使用 A* 寻路算法实现第二条最短路径,最好是第 n 条最短路径。我已经实现了最短路径:

while(open.length > 0) {
    max = worldSize;
    min = -1;
    for(i in open) {
        if(open[i].f < max) {
            max = open[i].f;
            min = i;
        }
    }

    node = open.splice(min, 1)[0];
    if(node.value === nodeEnd.value) {
        path = closed[closed.push(node)-1];
        do {
            result.push({x: path.x, y:path.y});
        } while(path = path.parent);
            open = closed = astar = [];
        result.reverse();
    } else {
        neighbors = findNeighbors(node.x, node.y);
        for(i = 0; i < neighbors.length; ++i) {
            path = newNode(node, neighbors[i]);
            if(!astar[path.value]) {
                path.g = node.g + manhattanDistance(neighbors[i], node);
                path.f = path.g + manhattanDistance(neighbors[i], nodeEnd);
                open.push(path);
                astar[path.value] = true;
            }

        }
        closed.push(node);
    }   
}

我能做什么?我在这方面的经验为零,甚至不完全理解算法(目前仍在研究)。谢谢。

【问题讨论】:

  • 一定要用A*吗?
  • 具有相同距离的路径是否符合第二短

标签: algorithm a-star


【解决方案1】:

所以这个问题通常是 NP 难题。由于您只需要第二条最短路径,因此您可以轻松完成。基本上,给定最短路径,您可以通过获取原始图并从最短路径中删除一条边来生成一组图。因此,如果您有一条长度为 N 的最短路径,在图 G(E,N) 上,您最终会得到 N 个 G(E-1,V) 的图。现在您在这些图上运行 A*,最短的一条是您的第二条最短路径,因为它是与原始最短路径至少有一条边不同的最短路径。

这也说明了为什么在实践中 NP 很难。如果我想要第三条最短路径,我必须执行以下过程,只从两条最短路径中的每一条中删除一条边,并且此类对的数量呈指数增长。 N->N^2->N^3 等

【讨论】:

  • 要找到常数 n 的第 n 条最短路径,这个问题显然需要多项式时间。您所做的只是表明您提出的解决方案需要 n 的指数时间 - 这不是您证明/显示 NP 硬度的方式。
  • 第 n^th 最短路径使用这种方法取 n^n,这是 n 的指数增长。显然这不是一个证明,但我相信这个问题通常被认为是 NP-Hard。显示 =/= 证明。
  • 顺便说一句,我相信第 k 条最快路线的解决方案等效于哈密顿路径问题的解决方案,即众所周知的 NP-HARD。见stackoverflow.com/questions/14088898/…
【解决方案2】:

if(node.value === nodeEnd.value) 是搜索终止条件。这意味着算法找到了从头到尾的一些路径。 A* 的本质,特别是启发式函数 (admissability and consistency) 的属性,保证了您第一次到达终止条件时会为您提供最短路径。

此外,可接受且一致的启发式方法还保证从开始到结束的所有可能路径始终从最短到最长检查

因此,为了获得第 N 条最近的路径,您只需要允许搜索算法继续 N-1 次,例如

hit_count = 0
while(open.length > 0) {
    // same as before
    if(node.value === nodeEnd.value) {
          path = closed[closed.push(node)-1];
          hit_count += 1;
          if (hit_count == N - 1) {
              do {
                  result.push({x: path.x, y:path.y});
              } while(path = path.parent);
              open = closed = astar = [];
              result.reverse();
          }
    }
    else { 
         // same as before
    }
}

请注意,这种方法将产生与新路径长度相同的路径,即,如果您有两条长度完全相同的路径,其中一条将被报告为最短,另一条被报告为第二短,具体取决于实施细节。

如果您想考虑所有具有相同长度“相同”的路径,因此“第二最短”实际上比最短路径长,只需将 hit_count += 1 替换为

// Don't forget to initialize last_found_path_length outside the loop to zero
if (path.length() != last_found_path_length) {
    last_found_path_length = path.length();
    hit_count += 1
}

请注意,您尚未指定它是什么语言(感觉像 Javascript),因此此处的示例可能包含语法错误或引用缺失的方法。但我希望方法是明确的。

【讨论】:

    【解决方案3】:

    一个近似的解决方案是多次运行 A* 算法,但需要注意的是:

    • 找到当前最短路径后
    • 标记在结束节点之前的节点
    • 下次运行算法时,不要使用该节点,例如将它的 path.f 值设置为无穷大或一些巨大的值。或者当它是您当前节点的邻居时,不要将其添加到打开列表中。
    • 新找到的路径将是下一个最短路径

    几点说明:

    • 这是近似值
    • 连接到末端的所有节点都循环通过后将无法工作。
    • 在具有复杂路径和障碍物的地形中,您可能会切断可能的路线
    • 如果下一个最短路径可以通过在路径查找算法中更早地做出决定来实现,您将不会捕获它。要捕获这一点,您必须以所述方式循环遍历整个路径,一次不允许一个节点并采用所有可能的计算路径中的最短路径 - 随着节点数量的增加,这将变得一团糟并迅速失控.

    希望有帮助。

    【讨论】:

      猜你喜欢
      • 2016-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-14
      • 2019-10-20
      • 1970-01-01
      相关资源
      最近更新 更多