如何从多路径Dijkstra重建路径?

时间:2017-05-10 20:07:06

标签: php algorithm graph path dijkstra

我目前正在为图表编写PHP库。我已经成功实现了单路径Dijkstra算法,但现在很难在路径重构阶段实现多路径版本。

采取以下图表:

Graph

为了简单起见,该图只有从顶点A到J的路径,经过多个其他顶点,这些顶点在成本上都是相等的,也就是说,每个路径的边缘权重加起来为10。 Dijkstra正确生成以下输出(即数组$this->prev):

Array
(
    [A] => 
    [B] => Array
        (
            [0] => A
        )

    [C] => Array
        (
            [0] => A
        )

    [D] => Array
        (
            [0] => C
        )

    [E] => Array
        (
            [0] => C
        )

    [F] => Array
        (
            [0] => E
            [1] => D
        )

    [G] => Array
        (
            [0] => A
        )

    [H] => Array
        (
            [0] => G
        )

    [I] => Array
        (
            [0] => H
        )

    [J] => Array
        (
            [0] => B
            [1] => F
            [2] => I
        )

)

当前的单路径Dijkstra路径重建算法如下实现:

public function get($dest)
{
    $destReal = $dest;
    $path = array();
    while (isset($this->prev[$dest])) {
        array_unshift($path, $dest);
        $dest = $this->prev[$dest];
    }
    if ($dest === $this->start) {
        array_unshift($path, $dest);
    }

    return array(
        'path' => $path,
        'dist' => $this->dist[$destReal]
    );
}

有没有办法修改上面的内容,以便它返回paths数组中的所有路径?我已经考虑过使用堆栈或DFS,但无法提出解决方案。我也尝试了foreach循环和递归,但没有用。

我基本上想要发生的是要按如下方式处理的结果:

  • J连接到B,B连接到A,因此$paths[0] = ['J', 'B', 'A']
  • J连接到F,F连接到E和D,因此继续通过E,记住返回F,然后通过D创建另一条路径,产生paths[1] = ['J', 'F', 'E', 'C', 'A']$paths[2] = ['J', 'F', 'D', 'C', 'A']
  • J连接到I,我连接到H,H连接到G,G连接到A,导致$paths[3] = ['J', 'I', 'H', 'G', 'A']

任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:0)

喜欢这个? (伪码):

function output_paths(source, dest, tail) {

    if source == dest:
        output([dest] + tail)

    for each node in prev[dest]:
        output_paths(source, node, [dest] + tail)
}


output_paths(source=A, dest=J, tail=[])

答案 1 :(得分:0)

实际上,我命名为“enumerate”的修改后的DFS函数解决了这个问题。为了后人的缘故,这里是我用来将多路径Dijkstra的输出转换为路径数组的代码:

/**
 * Returns all shortest paths to $dest from the origin vertex $this->start in the graph.
 *
 * @param string $dest ID of the destination vertex
 *
 * @return array An array containing the shortest path and distance
 */
public function get($dest)
{
    $this->paths = [];
    $this->enumerate($dest, $this->start);

    return array(
        'paths' => $this->paths,
        'dist' => $this->dist[$dest],
    );
}

/**
 * Enumerates the result of the multi-path Dijkstra as paths.
 *
 * @param string $source ID of the source vertex
 * @param string $dest   ID of the destination vertex
 */
private function enumerate($source, $dest)
{
    array_unshift($this->path, $source);
    $discovered[] = $source;

    if ($source === $dest) {
        $this->paths[] = $this->path;
    } else {
        if (!$this->prev[$source]) {
            return;
        }
        foreach ($this->prev[$source] as $child) {
            if (!in_array($child, $discovered)) {
                $this->enumerate($child, $dest);
            }
        }
    }

    array_shift($this->path);
    if (($key = array_search($source, $discovered)) !== false) {
        unset($discovered[$key]);
    }
}