如何判断有向图中是不是存在环

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何判断有向图中是不是存在环相关的知识,希望对你有一定的参考价值。

参考技术A 解法一:深度遍历
假设图以邻接矩阵表示,一条深度遍历路线中如果有结点被第二次访问到,那么有环。我们用一个变量来标记某结点的访问状态(未访问,访问过,其后结点都被访问过),然后判断每一个结点的深度遍历路线即可。
因为采用邻接矩阵存储,一般至少需要将矩阵中元素的一半给过一下,由于矩阵元素个数为n^2, 因此时间复杂度就是O(n^2)。如果采用邻接表存储,则只存储了边结点(e条边,无向图是2e条边),加上表头结点为n(也就是顶点个数),因此时间复杂度为O(n+e)。
解法二:拓扑排序
方法是重复寻找一个入度为0的顶点,将该顶点从图中删除(即放进一个队列里存着,这个队列的顺序就是最后的拓扑排序,具体见程序),并将该结点及其所有的出边从图中删除(即该结点指向的结点的入度减1),最终若图中全为入度为1的点,则这些点至少组成一个回路。
采用邻接矩阵存储时,遍历二维数组,求各顶点入度的时间复杂度是O(n^2)。 遍历所有结点,找出入度为0的结点的时间复杂度是O(n)。对于n个入度为0的结点,删除他们的出边的复杂度为O(n^2)。 所以总的复杂度为O(n^2)。
对于邻接表,遍历所有边,求各顶点入度的时间复杂度是O(e),即边的个数。遍历所有结点,找出入度为0的结点的时间复杂度是O(n),即顶点的个数。遍历所有边,删除入度为0的结点的出边的复杂度为O(e),即边的个数。所以总的时间复杂度是O(n+e)。

检查有向无环图中两个顶点之间是不是存在路径 - 查询

【中文标题】检查有向无环图中两个顶点之间是不是存在路径 - 查询【英文标题】:Check if there exist a path between two vertices in directed acyclic graph - queries检查有向无环图中两个顶点之间是否存在路径 - 查询 【发布时间】:2015-11-23 08:54:57 【问题描述】:

这个问题可以在每个查询 O(n + m) 中轻松解决,但是这是否可以通过比 O(n²) 更好的预处理来以更好的复杂性回答此类查询?

在树中,它可以通过使用预购和有序来轻松完成。我在 DAG 中尝试过类似的方法,但没有任何意义。

我也尝试将这个问题改成 LCA in DAG 问题,但是在 DAG 中找到 LCA 并不能足够快地解决。


为了精确的约束让我们说:

n - 顶点数,最多 10^5

m - 边数,最多 10^5

q - 查询数,最多 10^5

【问题讨论】:

即使在 DAG 中,也可能存在 O(n^2) 边(除非考虑到图形是稀疏的),因此您实际上是在寻找次线性时间......而 This question can be easily solved in O(n)不,出于同样的原因。 我的错。我的意思是 O(n + m)。 查询可以离线回答吗? 是的,欢迎离线解决方案。 【参考方案1】:

有趣的问题。我的直觉说“不”。不过我还没想好。

但是(假设这个问题不是理论上的问题),出于实际的目的,您可以使用Bloom filter。

使用 Bloom 过滤器解决问题的一种可能方法是首先生成 K 个不同顺序的图,并为每个顺序存储从节点到其索引的映射。然后,为了测试从 N1 到 N2 的“可达性”,您检查(foreach 顺序)是否 index-of-N1 小于 index-of-N2(此检查为 O(1))。如果这适用于所有订单,则很有可能达到 (assuming K is big enough)。 (根据您的实际用例,偶尔产生这样的误报甚至是可以的,或者您可以运行可靠的 O(N+M) 检查)。否则,绝对不是。

【讨论】:

【参考方案2】:

我感觉可能有一个解决方案,但这绝不是一个完整的解决方案。

令 S 为顶点的子集。对于图中的每个顶点 V,考虑集合 D_S(V),我定义如下:如果 V 在 S 中,则 D_S(V) = V,否则,D_S(V) 是 V 与V 的所有直接后代 W 的集合 D_S(W)。(也就是说,它是“V 的所有最终后代,但只要遇到 V 的元素就停止递归”。)问题是:我们能找到一个集合S 使得 S 的大小为 O(f(N)) 并且 D_S(V) 对于所有 V 的大小为 O(g(N)),并且 f 和 g 是渐近亚线性的? (例如,也许我们可以同时实现两者的 sqrt。)

如果我们能找到这个,那么我建议以下策略。对于预处理,为 S 中的每个 U 创建一个哈希表,其中包含最终从 U 到达的所有顶点。这可以在 O(f(N) * M) 中实现;这不一定比 O(N^2) 好,但至少比 O(M*Q) 好。

现在回答一个查询“U 是否可以从 V 到达?”,如果 V 在 S 中,这是微不足道的。否则,我们检查是否 V = U,在这种情况下它也是微不足道的。最后,我们将相同的过程应用于 V 的所有后代,递归地,如果通过上述两种情况之一的答案为“是”,则返回“是”,但只有当我们从未找到 U 时才返回“否”。这个递归占用O(g(N)) 步。

剩下的问题是如何选择 S。我认为,如果该图来自某个出度遵循幂律的过程,则可能只取具有最高出度的 sqrt(N) 个顶点。但是例如,如果我们有 N=2*K 个顶点 (i, 0) 和 (i, 1) 上的图,具有 K^2​​ 条边:从每个 (i, 0) 到每个 (j, 1);那么就没有合适的子集 S。但也许没有合适的 S 的图必然具有我们可以利用的某种程度的一致性……或者可能没有。我不知道。有什么想法,请告诉我!

【讨论】:

【参考方案3】:

任何用于 DAG 可达性查询的算法都可以通过压缩强连通分量来回答一般有向图上的此类查询。所以我认为 DAG 条件对降低复杂性没有任何作用。

至于有向图的可达性查询,this paper 中提到的索引构建技术可能对某些情况有所帮助。

【讨论】:

【参考方案4】:

如果您正在考虑通过一些预处理来提供快速的多个 path_exists(src_vertex, dest_vertex) 查询,请考虑调用Warshall's algorithm to determine the transitive closure,它会告知有向图中任意两个节点之间是否存在路径,作为预处理步骤(可能在服务器启动)。该算法的最坏情况时间复杂度为 O(n^3),空间复杂度为 O(n^2),其中 n 是节点数。该算法的输出是一个 nxn 矩阵,如果 node_i 和 node_j 之间存在路径,则 matrix[i][j] = 1,否则为零。因此,在查询服务时,您可以通过在传递闭包矩阵中查找 (i,j) 对,在 O(1) 时间内返回结果。

【讨论】:

以上是关于如何判断有向图中是不是存在环的主要内容,如果未能解决你的问题,请参考以下文章

c语言,有向图里如何检测是不是有环?

判断有向图是不是有环

如何判断一个图是不是为有向无环图(DAG)

判断有向图中是否存在环

Expm 9_1 有向图中环的判断问题

codeforces Gym 101572 I 有向图最小环路径