【问题标题】:Finding reachable vertices for every vertex in a directed graph为有向图中的每个顶点查找可达顶点
【发布时间】:2015-07-04 11:40:37
【问题描述】:

我知道执行此操作的蛮力方法是对图的所有顶点执行 DFS。因此,对于该算法,复杂度为 O(V|V+E|)。但是有没有更有效的方法来做到这一点?

【问题讨论】:

    标签: algorithm complexity-theory theory graph-theory


    【解决方案1】:

    我从http://research.microsoft.com/pubs/144985/todsfinal.pdf 之类的论文中得到的印象是,在一般情况下,没有比O(VE)O(V^3) 更好的算法。对于稀疏图和其他特殊图,有更快的算法。但是,如果您对将对数据进行的查询数量有所了解,您似乎仍然可以通过将“索引构造”与“查询”分开来进行改进。如果要进行大量查询,则O(1) 可以用于查询,前提是所有数据都已预先计算(DFS 或 Floyd-Warshall 等)并存储在O(n^2) 空间中。另一方面,如果查询相对较少,则可以以牺牲查询时间为代价来减少空间和/或索引构建时间。

    【讨论】:

      【解决方案2】:

      [编辑:正如 kraskevich 所指出的,最终的查询步骤可能比我最初声称的更糟糕:即使对于大小为 O(|V|) 的输出,也高达 O(|V|^2) ,比没有任何预处理的普通DFS好不了多少。].

      在最坏的情况下,需要 O(|V|^2) 空间来显式存储所有这些信息——即,存储每个顶点的可到达顶点的完整列表(想象一个图,其中每个顶点对每个其他顶点都有一条边)。但是可以用只需要 O(|V|) 空间的方式来表示它,并且这种表示可以在 O(|V|+|E|) 时间内构建, 并且对它的查询将只需要与答案大小(可达顶点数)成比例的时间

      基本思想是:一个strongly connected component(SCC)中的每个顶点都可以到达同一个SCC中的每个其他顶点(这是SCC的定义),并且可以到达它所能到达的SCC中的所有顶点,并且没有其他顶点。

      1. 查找所有 SCC;这可以在 O(|V|+|E|) 时间内完成。建立一个表SCC,使得如果u的SCC为i,则SCC(u) = i(G和SCC中的顶点都可以用整数表示)。然后再通过这个表构建一个对偶表 Verts,这样 Verts(i) 就包含了第 i 个 SCC 中所有顶点的列表。
      2. 构建一个新图 G',其顶点是 G 的 SCC。G' 必然是无环的。

      所以,给定 G 中的一个顶点 u,查找它的 SCC,SCC(u)。称之为我。从顶点 i 开始通过 G' 执行 DFS:对于在此 DFS 期间遇到的每个 (G') j 顶点,输出 Verts(j) 中的每个 (G) 顶点。

      【讨论】:

      • 实际上,看起来最坏情况下的时间与答案的大小不成正比。想象一个有三层的图。从第三层到第二层以及从第二层到第一层都有所有可能的边。它是一个 DAG,所以找到 SCC 并不会改变它。但是,从第三层的任何顶点运行 DFS 需要检查所有边(O(n^2)),但最多有O(n) 可达顶点。所以从第三层的所有顶点运行 DFS 会产生O(n^3) 时间,这并不比一个幼稚的解决方案好。
      • @kraskevich:你说的完全正确。我找不到解决办法...你可以吗?是否有某种方法可以有效地查询顶点的下一个子节点,从而避免已经看到的顶点?
      • @kraskevich:我现在意识到,如此高效的查询意味着 DFS 可以在少于 O(|V|+|E|) 的时间内完成!
      【解决方案3】:

      我真的怀疑没有已知的更好的通用图算法。我在主题 [1] [2] 上找到的所有论文都描述了在 O(|V| * |E|) 时间内运行的算法。这并不比你在最坏情况下的幼稚尝试更好。

      即使是维基百科页面 [3] 也说最快的算法将问题简化为矩阵乘法,最快的算法只比你的基线稍微好一点。

      [1]http://ion.uwinnipeg.ca/~ychen2/conferencePapers/tranRelationCopy.pdf

      [2]http://www.vldb.org/conf/1988/P382.PDF

      [3]http://en.wikipedia.org/wiki/Transitive_closure#Algorithms

      【讨论】:

      • 能否请您解释一下如何将快速乘法应用于此问题
      • @teja 不知道有没有更快的算法,但是可以使用邻接矩阵M,执行M^|V|。使用最快的矩阵乘法算法(和平方求幂),这是 O(|V|^2.37 log |V|)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-15
      • 1970-01-01
      • 1970-01-01
      • 2020-07-30
      相关资源
      最近更新 更多