我有一个依赖图,我将其表示为 Map>
(用 Java 语言,或 f(Node n) -> Collection[Node]
作为一个函数;这是从给定节点 n
到依赖于 n
的节点集合的映射。该图可能是循环的*。
给定一个节点列表 badlist
,我想解决可达性问题:即生成一个Map>; badmap
表示从列表 badlist
中的每个节点 N 到包含 N 或传递依赖于它的其他节点的一组节点的映射。
示例:
(x -> y means node y depends on node x)
n1 -> n2
n2 -> n3
n3 -> n1
n3 -> n5
n4 -> n2
n4 -> n5
n6 -> n1
n7 -> n1
这可以表示为邻接图 {n1: [n2], n2: [n3], n3: [n1, n5], n4: [n2, n5], n6: [n1], n7: [n1]}
。
如果 badlist = [n4, n5, n1]
那么我期望得到 badmap = {n4: [n4, n2, n3, n1, n5], n5: [n5], n1: [n1,n2,n3,n5]}
。
我正在努力寻找在线图算法参考,所以如果有人能给我指出一个有效的可达性算法描述,我将不胜感激。 (对我没有帮助的一个例子是 http://www.cs.fit.edu/~wds/classes/cse5081/reach/reach.html 因为该算法是确定从特定节点是否可以到达特定节点 A B.)
*循环:如果您好奇,这是因为它代表 C/C++ 类型,并且结构可以具有指向相关结构的指针的成员。
I have a dependency graph that I have represented as a Map<Node, Collection<Node>>
(in Java-speak, or f(Node n) -> Collection[Node]
as a function; this is a mapping from a given node n
to a collection of nodes that depend on n
). The graph is potentially cyclic*.
Given a list badlist
of nodes, I would like to solve a reachability problem: i.e. generate a Map<Node, Set<Node>> badmap
that represents a mapping from each node N in the list badlist
to a set of nodes which includes N or other node that transitively depends on it.
Example:
(x -> y means node y depends on node x)
n1 -> n2
n2 -> n3
n3 -> n1
n3 -> n5
n4 -> n2
n4 -> n5
n6 -> n1
n7 -> n1
This can be represented as the adjacency map {n1: [n2], n2: [n3], n3: [n1, n5], n4: [n2, n5], n6: [n1], n7: [n1]}
.
If badlist = [n4, n5, n1]
then I expect to get badmap = {n4: [n4, n2, n3, n1, n5], n5: [n5], n1: [n1, n2, n3, n5]}
.
I'm floundering with finding graph algorithm references online, so if anyone could point me at an efficient algorithm description for reachability, I'd appreciate it. (An example of something that is not helpful to me is http://www.cs.fit.edu/~wds/classes/cse5081/reach/reach.html since that algorithm is to determine whether a specific node A is reachable from a specific node B.)
*cyclic: if you're curious, it's because it represents C/C++ types, and structures can have members which are pointers to the structure in question.
发布评论
评论(6)
在Python中:
In Python:
这是我最终使用的,基于 @quaint 的答案:(
为了方便起见,需要一些 Guava 类)
here's what I ended up using, based on @quaint's answer:
(requires a few Guava classes for convenience)
您也许应该从邻接列表中构建一个可达性矩阵以进行快速搜索。我刚刚找到了论文 CS336 课程笔记:图表理论 - 贾亚德夫·米斯拉
描述了如何从邻接矩阵构建可达性矩阵。
如果
A
是邻接矩阵,则可达性矩阵将为R = A + A² + ... + A^n
,其中n
是图中的节点数。A², A³, ...
计算公式如下:A² = A x A
A³ = A x A²
对于矩阵乘法逻辑或用于代替
+
,逻辑与用于代替x
。复杂度为O(n^4)。You maybe should build a reachability matrix from your adjacency list for fast searches. I just found the paper Course Notes for CS336: Graph Theory - Jayadev Misra
which describes how to build the reachability matrix from a adjacency matrix.
If
A
is your adjacency matrix, the reachability matrix would beR = A + A² + ... + A^n
wheren
is the number of nodes in the graph.A², A³, ...
can be calculated by:A² = A x A
A³ = A x A²
For the matrix multiplication the logical or is used in place of
+
and the logical and is used in place ofx
. The complexity is O(n^4).普通的深度优先搜索或广度优先搜索就可以解决问题:对每个坏节点执行一次。
Ordinary depth-first search or breadth-first search will do the trick: execute it once for each bad node.
这是一个有效的 Java 解决方案:
Here's a working Java solution:
就像 Christian Ammer 一样,在执行以下操作时,您将邻接矩阵视为
A
并使用布尔算术,其中I
是单位矩阵。此外,标准矩阵乘法(算术和逻辑)是
O(n^3)
,而不是O(n^2)
。但是,如果n <= 64
,您就可以摆脱一个因素n
,因为您可以在当今的 64 位机器上并行执行 64 位操作。对于较大的图形,64 位并行性也很有用,但着色器技术可能更好。编辑:可以与 SSE 指令并行执行 128 位,使用 AVX 指令甚至更多。
Just like with Christian Ammer, you take for
A
the adjacency matrix and use Boolean arithmetic, when doing the following, whereI
is the identity matrix.Furthermore, standard matrix multiplication (both arithmetical and logical) is
O(n^3)
, notO(n^2)
. But ifn <= 64
, you can sort of get rid of one factorn
, because you can do 64 bits in parallel on nowadays 64 bits machines. For larger graphs, 64 bits parallelism is useful, too, but shader techniques might even be better.EDIT: one can do 128 bits in parallel with SSE instructions, with AVX even more.