检查有向无环图中两个顶点之间是不是存在路径 - 查询
Posted
技术标签:
【中文标题】检查有向无环图中两个顶点之间是不是存在路径 - 查询【英文标题】: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) 时间内返回结果。
【讨论】:
以上是关于检查有向无环图中两个顶点之间是不是存在路径 - 查询的主要内容,如果未能解决你的问题,请参考以下文章