0

给定一个 DAG 的邻接列表Map<Vertex, Set<Vertex>>,我想计算每个顶点的可达性(即是否存在从 u 到 v 的路径)。

static Map<Vertex, Set<Vertex>> reachability(Map<Vertex, Set<Vertex>> adjList) {}

我知道使用 Floyd-Warshall 是可能的O(V^3)

// Convert adjList to adjacency matrix mat
void reachability(boolean mat[][]) {
  final int N = mat.length;
  for (int k = 0; k < N; k++)
    for (int i = 0; i < N; i++)
      for (int j = 0; j < N; j++)
        mat[i][j] |= mat[i][k] && mat[k][j];
}

但是我有一个稀疏图(和一个邻接表),那么最快的方法是什么?

4

2 回答 2

2

一个O(V*(V+E))解决方案可能是从图中的每个节点执行一个简单的BFS并计算其可达性集。假设|E| << |V|^2(您说图形是稀疏的),这比 floyd-warshall 快得多(并且编码更简单)。

但是,这仍然不是最理想的,可以改进:

您的图是一个 DAG,因此您可以先在 中进行拓扑排序O(V+E)然后从最后一个到第一个:

连接(v)=联合{连接(u)| 对于所有边 (v,u) } U {v}

这可以非常有效地计算出来,并给出时间复杂度的总答案,O(|V|+|E|+k)其中 |V| - 顶点数,|E| - 边数,k - 连接对的数量(仅限O(|V|^2)于最坏的情况)。

即使对于非稀疏图,此解决方案也会为您提供O(|V|^2)最差的性能。

伪代码:

V = [v0,v1,...,vn-1]
V = topological_sort(V) //O(V+E)
connect = new Map:V->2^V //Map<Vertex,Set<Vertex>> in java
i = n-1
while (i >= 0):
   let v be the vertex in V[i]
   connected[v].add(v)
   for each edge (v,u):
      //since the graph is DAG, and we process in reverse order
      //the value of connected[u] is already known, so we can use it.
      connected[v].addAll(connected[u])
于 2015-07-14T22:08:18.127 回答
0

这是 Scala 中的一个简单O(|V||E|)解决方案(基本上,对于每个顶点,做一个 DFS):

type AdjList[A] = Map[A, Set[A]]

def transitiveClosure[A](adjList: AdjList[A]): AdjList[A]  = {
  def dfs(seen: Set[A])(u: A): Set[A] = {
    require(!seen(u), s"Cycle detected with $u in it")
    (adjList(u) filterNot seen flatMap dfs(seen + u)) + u
  }
  adjList.keys map {u =>
    u -> dfs(Set.empty)(u)  
  } toMap
}

此处的可执行版本:http: //scalafiddle.net/console/4f1730a9b124eea813b992edebc06840

于 2015-07-16T17:56:10.543 回答