问题
I am currently writing a PHP library for graphs. I have already implemented a single-path Dijkstra's algorithm successfully, but now struggle with implementing a multi-path version at the path reconstruction stage.
Take following graph:
This graph, for the sake of simplicity, has only paths from vertex A to J, going through multiple other vertices, which are all equal in cost, that is, the edge weight for each path add up to 10. The modified Dijkstra correctly produces the following output (which is the array $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
)
)
The current, single-path Dijkstra path reconstruction algorithm is implemented as such:
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]
);
}
Is there a way to modify the above, such that it returns me all the paths in a paths array? I have already thought about using maybe a stack or DFS, but couldn't come up with a solution. I also gave foreach loops and recursion a try, to no avail.
What I essentially want to happen is the result to be processed as follows:
- J connects to B, B connects to A, hence
$paths[0] = ['J', 'B', 'A'] - J connects to F, F connects to E and D, hence continue on through E, remembering to return to F, then create another path through D, resulting in
paths[1] = ['J', 'F', 'E', 'C', 'A']and$paths[2] = ['J', 'F', 'D', 'C', 'A'] - J connects to I, I connects to H, H connects to G and G connects to A, resulting in
$paths[3] = ['J', 'I', 'H', 'G', 'A']
Any help would be appreciated!
回答1:
Like this? (Pseudocode):
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=[])
回答2:
Actually, a modified DFS function I named "enumerate" solved this question. For posterity's sake, here is the code I used to turn the output of the multi-path Dijkstra into an array of paths:
/**
* 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]);
}
}
来源:https://stackoverflow.com/questions/43901833/how-to-reconstruct-paths-from-a-multi-path-dijkstra