我有一个依赖图,我将其表示为Map<Node, Collection<Node>>
(在Java语言中,或f(Node n) -> Collection[Node]
作为函数;这是从给定节点n
到a的映射依赖n
)的节点集合。该图可能是循环*。
给定节点列表badlist
,我想解决reachability problem:即生成Map<Node, Set<Node>> 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 ++类型,而结构可以有成员指向有问题的结构。
答案 0 :(得分:3)
在Python中:
def reachable(graph, badlist):
badmap = {}
for root in badlist:
stack = [root]
visited = set()
while stack:
v = stack.pop()
if v in visited: continue
stack.extend(graph[v])
visited.add(v)
badmap[root] = visited
return badmap
答案 1 :(得分:2)
这是我最终使用的内容,基于@ quaint的回答:
(为方便起见,需要一些番石榴类)
static public <T> Set<T> findDependencies(
T rootNode,
Multimap<T, T> dependencyGraph)
{
Set<T> dependencies = Sets.newHashSet();
LinkedList<T> todo = Lists.newLinkedList();
for (T node = rootNode; node != null; node = todo.poll())
{
if (dependencies.contains(node))
continue;
dependencies.add(node);
Collection<T> directDependencies =
dependencyGraph.get(node);
if (directDependencies != null)
todo.addAll(directDependencies);
}
return dependencies;
}
static public <T> Multimap<T,T> findDependencies(
Iterable<T> rootNodes,
Multimap<T, T> dependencyGraph)
{
Multimap<T, T> dependencies = HashMultimap.create();
for (T rootNode : rootNodes)
dependencies.putAll(rootNode,
findDependencies(rootNode, dependencyGraph));
return dependencies;
}
static public void testDependencyFinder()
{
Multimap<Integer, Integer> dependencyGraph =
HashMultimap.create();
dependencyGraph.put(1, 2);
dependencyGraph.put(2, 3);
dependencyGraph.put(3, 1);
dependencyGraph.put(3, 5);
dependencyGraph.put(4, 2);
dependencyGraph.put(4, 5);
dependencyGraph.put(6, 1);
dependencyGraph.put(7, 1);
Multimap<Integer, Integer> dependencies =
findDependencies(ImmutableList.of(4, 5, 1), dependencyGraph);
System.out.println(dependencies);
// prints {1=[1, 2, 3, 5], 4=[1, 2, 3, 4, 5], 5=[5]}
}
答案 2 :(得分:2)
您可能应该从邻接列表中构建可达性矩阵以进行快速搜索。我刚刚找到了论文Course Notes for CS336: Graph Theory - Jayadev Misra ,它描述了如何从邻接矩阵构建可达性矩阵。
如果A
是您的邻接矩阵,则可达性矩阵将为R = A + A² + ... + A^n
,其中n
是图中的节点数。 A², A³, ...
可以通过以下方式计算:
A² = A x A
A³ = A x A²
对于矩阵乘法,使用逻辑或代替+
,并使用逻辑和代替x
。复杂度为O(n ^ 4)。
答案 3 :(得分:1)
普通的深度优先搜索或广度优先搜索将解决这个问题:为每个坏节点执行一次。
答案 4 :(得分:1)
这是一个有效的Java解决方案:
// build the example graph
Map<Node, Collection<Node>> graph = new HashMap<Node, Collection<Node>>();
graph.put(n1, Arrays.asList(new Node[] {n2}));
graph.put(n2, Arrays.asList(new Node[] {n3}));
graph.put(n3, Arrays.asList(new Node[] {n1, n5}));
graph.put(n4, Arrays.asList(new Node[] {n2, n5}));
graph.put(n5, Arrays.asList(new Node[] {}));
graph.put(n6, Arrays.asList(new Node[] {n1}));
graph.put(n7, Arrays.asList(new Node[] {n1}));
// compute the badmap
Node[] badlist = {n4, n5, n1};
Map<Node, Collection<Node>> badmap = new HashMap<Node, Collection<Node>>();
for(Node bad : badlist) {
Stack<Node> toExplore = new Stack<Node>();
toExplore.push(bad);
Collection<Node> reachable = new HashSet<Node>(toExplore);
while(toExplore.size() > 0) {
Node aNode = toExplore.pop();
for(Node n : graph.get(aNode)) {
if(! reachable.contains(n)) {
reachable.add(n);
toExplore.push(n);
}
}
}
badmap.put(bad, reachable);
}
System.out.println(badmap);
答案 5 :(得分:0)
就像使用Christian Ammer一样,在执行以下操作时,您需要A
邻接矩阵并使用布尔算法,其中I
是单位矩阵。
B = A + I;
C = B * B;
while (B != C) {
B = C;
C = B * B;
}
return B;
此外,标准矩阵乘法(算术和逻辑)均为O(n^3)
,而不是O(n^2)
。但是如果n <= 64
,你可以摆脱一个因素n
,因为你现在可以在64位机器上并行执行64位。对于较大的图形,64位并行性也很有用,但着色器技术甚至可能更好。
编辑:一个可以与SSE指令并行执行128位,AVX甚至更多。