考虑以下图表:
由以下数组结构表示:
$graph = array
(
'a' => array(),
'b' => array('a'),
'c' => array('a', 'b'),
'd' => array('a'),
'e' => array('d'),
'f' => array('a', 'b', 'c', 'd'),
'g' => array('d'),
'h' => array('c'),
'i' => array('c', 'g'),
'j' => array(),
);
在没有重复节点的情况下,从节点X到节点Y 找到所有路径(不仅是最短路径)的最有效算法是什么??例如,从节点C
到节点A
的路径是:
C --> A
C --> B --> A
C --> F --> A
C --> F --> B --> A
C --> F --> D --> A
C --> I --> G --> D --> A
使用节点X
(A
和B
的父节点查找所有路径,在节点C
的示例中)是微不足道的,但我有一个很难在后代/混合方向上遍历节点。
有人能帮助我吗?
更新:在@JackManey建议之后,我尝试根据维基百科的伪代码移植IDDFS(Iterative Deepening Depth-First Search),这或多或少是我的代码看起来像:
$graph = directed2Undirected($graph);
function IDDFS($root, $goal) {
$depth = 0;
while ($depth <= 2) { // 2 is hard-coded for now
$result = DLS($root, $goal, $depth);
if ($result !== false) {
return $result;
}
$depth++;
}
}
function DLS($node, $goal, $depth) {
global $graph;
if (($depth >= 0) && ($node == $goal)) {
return $node;
}
else if ($depth > 0) {
foreach (expand($node, $graph) as $child) {
return DLS($child, $goal, $depth - 1);
}
}
else {
return false;
}
}
以下是它使用的辅助函数:
function directed2Undirected($data) {
foreach ($data as $key => $values) {
foreach ($values as $value) {
$data[$value][] = $key;
}
}
return $data;
}
function expand($id, $data, $depth = 0) {
while (--$depth >= 0) {
$id = flatten(array_intersect_key($data, array_flip((array) $id)));
}
return array_unique(flatten(array_intersect_key($data, array_flip((array) $id))));
}
function flatten($data) {
$result = array();
if (is_array($data) === true) {
foreach (new RecursiveIteratorIterator(new RecursiveArrayIterator($data)) as $value) {
$result[] = $value;
}
}
return $result;
}
调用上述内容会产生奇怪或不完整的结果:
var_dump(IDDFS('c', 'a')); // a -- only 1 path?
var_dump(IDDFS('c', 'd')); // NULL -- can't find this path?!
我认为我忽略了伪代码中的某些内容,但我不确定它是什么。
我还尝试了另一个问题中推荐的this DFS class,虽然它似乎总是找到从节点X到节点Y的一条路径,但我无法让它返回所有路径(C
-> A
和C
-> D
的演示)。
由于我不需要知道实际采用的路径,因此只有存在需要n
个步骤从节点X到节点Y的路径数量,I提出了这个功能(使用上面的directed2Undirected
):
$graph = directed2Undirected($graph);
function Distance($node, $graph, $depth = 0) {
$result = array();
if (array_key_exists($node, $graph) === true) {
$result = array_fill_keys(array_keys($graph), 0);
foreach (expand($node, $graph, $depth - 1) as $child) {
if (strcmp($node, $child) !== 0) {
$result[$child] += $depth;
}
}
$result[$node] = -1;
}
return $result;
}
function expand($id, $data, $depth = 0) {
while (--$depth >= 0) {
$id = flatten(array_intersect_key($data, array_flip((array) $id)));
}
// no array_unique() now!
return flatten(array_intersect_key($data, array_flip((array) $id)));
}
对于Distance('c', $graph, 0)
,Distance('c', $graph, 1)
和Distance('c', $graph, 2)
,这会正确返回C
与任何其他节点之间距离的总和。问题是,Distance('c', $graph, 3)
(and higher)会重复节点并返回错误的结果:
Array
(
[a] => 12
[b] => 9
[c] => -1
[d] => 9
[e] => 3
[f] => 12
[g] => 3
[h] => 3
[i] => 6
[j] => 0
)
索引a
应该只有6(3 + 3),因为我使用3个步骤从C
到A
的唯一方法是:
C --> F --> B --> A
C --> F --> D --> A
然而,它似乎正在考虑重复节点的 两个 (仅?)其他路径:
C --> A --> C --> A
C --> B --> C --> A
C --> F --> C --> A
C --> H --> C --> A
C --> I --> C --> A
当然,索引a
并不是唯一错误的。问题似乎是expand()
,但我不确定如何修复它,array_diff(expand('c', $graph, $i), expand('c', $graph, $i - 2))
似乎解决了这个特定的错误,但是那个正确的修复...帮助?< / p>
再次 ,所以你不必滚动
答案 0 :(得分:2)
一般来说,你可以做一个depth-first search或breadth-first search,虽然没有一个优于另一个(因为很容易想出一个优于另一个的例子)。
编辑:在重新阅读问题并思考一下后,由于您希望从C
到A
的所有路径,从C
开始的DFS可能会最有意义的。在此过程中,如果它们不在A
结束,则必须存储边缘序列并抛出序列。
答案 1 :(得分:0)
$ stdin = fopen('php:// stdin','r'); $ stdin = fopen('php:// stdin','w');
fscanf(STDIN,"%d\n",$n);
fscanf(STDIN,"%d\n",$e);
$graph = array();
for ($i = 0;$i<$n; $i++)
{
$graph[$i] = array();
}
for ($i = 0;$i<$e; $i++)
{
fscanf(STDIN,"%s%s",$x,$y);
$row = ord($x[0]) - ord('A');
$row = ord($y[0]) - ord('A');
echo $row." ".$col;
$graph[$row][$col] = 1;
$graph[$col][$row] = 1;
}
for ($i = 0;$i <$n; $i++)
{
for ($j= 0;$j<$n ;$j++)
{
if ($graph[$i][$j]==1)
{
echo"1 ";
}
else{
echo"0 ";
}
echo "\n";
}
}