我目前正在为图形编写PHP库。我已经成功地实现了单路径Dijkstra的算法,但是现在在路径重构阶段难以实现多路径版本。
拍下图:
为了简单起见,此图仅具有从顶点A到J的路径,并且经过多个其他顶点,这些路径的成本均相等,也就是说,每条路径的边权重总计为10。修改后的Dijkstra正确生成以下输出(是array $this->prev):
$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尝试了循环和递归,但无济于事。
paths
foreach
我本质上想要发生的是按以下方式处理结果:
$paths[0] = ['J', 'B', 'A']
paths[1] = ['J', 'F', 'E', 'C', 'A']
$paths[2] = ['J', 'F', 'D', 'C', 'A']
$paths[3] = ['J', 'I', 'H', 'G', 'A']
任何帮助,将不胜感激!
实际上,我命名为“枚举”的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]); } }