我目前正在为图表编写PHP库。我已经成功实现了单路径Dijkstra算法,但现在很难在路径重构阶段实现多路径版本。
采取以下图表:
为了简单起见,该图只有从顶点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
循环和递归,但没有用。
我基本上想要发生的是要按如下方式处理的结果:
$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']
任何帮助将不胜感激!
答案 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]);
}
}