循环无向图中的所有可能路径

Posted

技术标签:

【中文标题】循环无向图中的所有可能路径【英文标题】:All possible paths in a cyclic undirected graph 【发布时间】:2010-06-17 05:02:32 【问题描述】:

我正在尝试开发一种算法来识别图中两个节点之间的所有可能路径,如下例所示:

.

实际上,我只需要知道哪些节点出现在所有现有路径中。

在网络上只有关于 DFS、A* 或 dijkstra 的参考资料,但我认为它们在这种情况下不起作用。

有人知道怎么解决吗?

【问题讨论】:

家庭作业?到目前为止,您尝试过什么? 如果图是循环的,会不会有无限多的路径? @jalf,我也这么认为,但***说存在一些分歧。 “没有重复顶点的路径称为简单路径,除了开始和结束顶点的必要重复之外,没有重复顶点或边的循环是简单循环。在现代图论中,最常见的是“简单” ; 即,“循环”表示“简单循环”,“路径”表示“简单路径”,但并不总是遵守这种约定,尤其是在应用图论中。” 【参考方案1】:

您可以像 |Vlad 描述的那样使用 DFS 找到所有路径。要查找每个路径中出现的节点,您只需维护一个布尔数组,该数组表示到目前为止每个节点是否出现在每个路径中。当您的 DFS 找到路径时,遍历路径中的每个顶点 not 并将相应的数组值设置为 false。完成后,只有值为 true 的顶点才会出现在每条路径中。

伪代码:

int source;
int sink;
int nVerts;
bool inAllPaths[nVerts]; // init to all true
bool visited[nVerts]; // init to all false
stack<int> path; // init empty

bool dfs(int u)
  if (visited[u])
    return;
  if (u == sink)
    for i = 0 to nVerts-1
      if !stack.contains(i)
        inAllPaths[i] = false;
    return true;
  else
    visited[u] = true;
    stack.push(u);
    foreach edge (u, v)
      dfs(v);
    stack.pop();
    visited[u] = false;
    return false;


main()
  dfs(source);
  // inAllPaths contains true at vertices that exist in all paths
  // from source to sink.

但是,这种算法效率不高。例如,在一个包含 n 个顶点(所有顶点与所有其他顶点之间都有边)的完整图中,路径的数量将是 n! (n 阶乘)。

更好的算法是分别检查每个顶点的每条路径中是否存在。对于每个顶点,尝试找到从源到汇的路径,而不是去那个顶点。如果找不到,那是因为顶点出现在每条路径中。

伪代码:

// Using the same initialisation as above, but with a slight modification
// to dfs: change the foreach loop to
foreach edge (u, v)
  if (dfs(v))
    return true; // exit as soon as we find a path

main()
  for i = 0 to nVerts-1
    set all visited to false;
    if (inAllPaths[i])
      visited[i] = true;
      if (dfs(source))
        inAllPaths[i] = false;
      visited[i] = false;

不幸的是,在搜索路径时,这仍然是指数级的最坏情况。您可以通过将搜索更改为广度优先搜索来解决此问题。如果我没记错的话,这应该会给你 O(VE) 性能。

【讨论】:

【参考方案2】:

从您的起始节点运行 DFS 并保留您自己的堆栈,该堆栈会告诉您在任何给定时间看到的节点。注意循环:当你看到一个节点两次时,你就有了一个循环,你必须中止当前的路径。注意不要访问节点的父节点,以免循环长度为 1(在 DFS 函数中添加 parent 参数,这会有所帮助)。

然后,当您到达目标节点时,输出堆栈的内容。

DFS 完成后,您将拥有所有路径。

【讨论】:

【参考方案3】:

对于这个问题,我首先会从你的一个目标节点 u 上的 DFS 中获取树 t。然后,将所有节点着色,比如说蓝色,它们位于以您的第二个目标节点 v 为根的子树 s 中。

For each node k in subtree s, 
    if k has an edge to a non-blue node x 
    then k is true and x is true.

另外,将 v 标记为 true。最后,我会使用递归函数直到叶子。类似的东西

function(node n)
    if(n = null)
        return false
    if(function(n.left) or function(n.right) or n.val)
        n.val = true
        return true
    
    else
        return false

所有标记为 true 的节点都是从 u 到 v 的路径中的节点。运行时间最多为 (Vertices + Edges),因为 DFS = (V+E) 最多 for 循环 (V) 最多递归(五)

【讨论】:

【参考方案4】:

我知道已经有一段时间了,但我来这里是为了寻找一些算法来查找 SQL 或 Java 中的所有路径(不仅是最短路径),我找到了这三个(我只是发布它们以保持概念的组织):

Java

http://introcs.cs.princeton.edu/java/45graph/AllPaths.java.html(依赖项:Graph、ST、Set、In,在http://introcs.cs.princeton.edu/java/45graph/中找到)

SQL (PostgreSQL)。

查看WITH RECURSIVE transitive_closure(a, b, distance, path_string) AS

http://techportal.inviqa.com/2009/09/07/graphs-in-the-database-sql-meets-social-networks/

PL/SQL (甲骨文)

https://forums.oracle.com/forums/thread.jspa?threadID=2415733

select pth as "Path", distance as "Distance"
from (
  select connect_by_root(n1) || sys_connect_by_path(n2,'>') pth ,n2, level as distance
  from -- Edge List Table
    (select 'A' n1,'B' n2 from dual
    union all select 'A','C' from dual
    union all select 'B','C' from dual
    union all select 'B','D' from dual
    union all select 'D','G' from dual
    union all select 'C','G' from dual
    union all select 'D','I' from dual
    union all select 'C','E' from dual
    union all select 'E','F' from dual
    union all select 'F','G' from dual
    union all select 'F','H' from dual   
    ) links
  start with n1='A'
  connect by nocycle prior n2=n1)
  where n2 = 'G';

结果:

Distance    Path
3   A>B>C>G
5   A>B>C>E>F>G
3   A>B>D>G
2   A>C>G
4   A>C>E>F>G

如果您在 cmets 中输入 start with n1...where n2... 行,查询将返回所有图表中的所有路径。

【讨论】:

【参考方案5】:

一个顶点在从 A 到 B 的路径上,如果它可以从 A 到达,并且 B 可以从它到达。

所以:从 A 开始进行泛洪填充。标记所有这些顶点。 从 B 开始并沿反向边缘进行填充。您遇到的所有标记顶点都是解决方案的一部分。

【讨论】:

以上是关于循环无向图中的所有可能路径的主要内容,如果未能解决你的问题,请参考以下文章

新知识添加·欧拉回路+欧拉路径

在具有特定成本的无向图中查找路径

在无向图中查找多边形

欧拉回路混合图的欧拉回路

有向/无向图中搜环

通过无向无环图查找所有路径