簡體   English   中英

在無向圖中查找路徑

[英]Finding paths in a Undirected 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的父節點(在節點C的示例中為AB查找所有路徑是微不足道的,但是我很難在后代/混合方向上遍歷節點。

有人可以幫我嗎?


更新 :在@JackManey建議之后,我嘗試根據Wikipedia偽代碼移植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?!

我想我忽略了偽代碼中的某些東西,但我不確定它是什么。


我也嘗試過在另一個問題中推薦的這個DFS類 ,雖然它似乎總是找到從節點X到節點Y的一條路徑,我無法讓它返回所有路徑(演示C - > AC - > 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) 更高 ),它開始重復節點並返回錯誤的結果:

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個步驟從CA的唯一方法是:

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))似乎修復此特定錯誤,但這不是一個正確的修復...幫助?


虛擬圖再次 再次,所以你不必滾動

一般來說,你可以進行深度優先搜索廣度優先搜索 ,雖然沒有一個優於另一個(因為很容易想出一個優於另一個的例子)。

編輯:在重新閱讀的問題和思考了一下,因為你想從所有路徑CA ,一個DFS開始C很可能最有意義。 一路上,你必須存儲邊緣序列並拋棄序列,如果它們不是最終在A

$ 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";
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM