最有效的算法来计算无向图中需要 N 步骤的所有路径

问题描述 投票:0回答:2

考虑下图:

dummy graph

用如下数组结构表示:

$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(迭代加深深度优先搜索),这或多或少是我的代码的样子:

$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?!

我认为我从伪代码中忽略了一些东西,但我不确定它是什么。


我还尝试了另一个问题中推荐的这个DFS类,虽然它似乎总是找到从节点X到节点Y的one路径,但我无法让它返回所有路径(

C
的演示) ->
A
C
->
D
)。


由于我不需要知道实际采取的路径,只需要知道有多少条路径需要

n
步数才能从节点X到达节点Y,所以我想出了这个函数(使用上面的
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)
andhigher)它开始重复节点并返回错误的结果:

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))
似乎修复了这个特定的错误,但这不是一个正确的修复。


dummy graph again 再次,这样您就不必滚动

php algorithm charts graph-theory undirected-graph
2个回答
2
投票

一般来说,您可以进行深度优先搜索广度优先搜索,尽管两者都不优于另一个(因为很容易想出一个优于另一个的示例)。

编辑:重新阅读问题并思考一下后,由于您想要从

C
A
的所有路径,因此从
C
开始的 DFS 可能最有意义。在此过程中,您必须存储边序列,如果它们没有到达
A
,则将其丢弃。


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";
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.