有时候我们需要知道有向图 G = (V, E)的顶点之间是否存在路径。 那么怎样确定有向图中每对顶点之间是否存在路径呢? 这涉及到一个非常重要的概念—— 有向图的传递闭包。
有向图G的传递闭包定义为 G' = (V, E'), 其中 E' = {(u, v) | 图 G 中存在一条从顶点 u 到顶点 v 的路径}。
我们可在O(n^3)(n为图G中的顶点数)的时间复杂度内计算出有向图的传递闭包。
Floyd-Warshall算法(每对顶点间最短路径算法, 对其做了一些改动, 来计算传递闭包):
1 // G = (V, E), V = {1, 2, ..., n} 2 3 tu[i][j] = false for all possible i and j. // in fact 1 <= i, j <= n 4 5 for each edge (u, v) 6 tc[u][v] = true; 7 8 for (k = 1; k <= n; k++) 9 for (i = 1; i <= n; i++) 10 for (j = 1; j <= n; j++) 11 tc[i][j] ||= (tc[i][k] && tc[k][j]); 12 13 14 // then the transitive closure of G : G' = (V, E'), where E' = {(u, v) | tc[u][v] = true}. :)
此外,存在时间复杂度为O(nm)的算法(n = |V|, m = |E|)。 算法的伪代码如下:
// Give an O(VE)-time algorithm for computing the transitive closure of a directed // graph G = (V, E). // We compute the transitive closure as an adjacency matrix, TC[i, j] // Assume that each vertex v has a unique identification number: // // id(v) ∈ {0, 1, 2, …, |V| - 1} // for each vertex u perform a BFS or DFS with u as the root for each vertex v discovered in the search TC[id(u), id(v)] = 1 return TC // In the extreme case, a search can traverse every edge in the dataflow graph. Hence, // the total time complexity of this algorithm is O(VE).
POJ 3275:
答案: n*(n-1)/2 - |E'|, E'为输入有向图的传递闭包的边集。
C++代码:
1 #include <stdio.h> 2 3 #define N 1001 4 #define M 10000 5 6 int stack[N], top = -1; 7 bool instack[N] = {false}; 8 9 struct s_edge { 10 int node, next; 11 } edge[M]; 12 int adj[N]; 13 14 int n, m; 15 16 bool tc[N][N] = {false}; 17 18 void dfs(int u) { 19 int v, i; 20 for (i = adj[u]; i != -1; i = edge[i].next) { 21 v = edge[i].node; 22 if (!instack[v]) { 23 stack[++top] = v; 24 instack[v] = true; 25 dfs(v); 26 } 27 } 28 } 29 30 int main() { 31 int count, i, j, k; 32 scanf("%d%d", &n, &m); 33 for (i = 1; i <= n; i++) { 34 adj[i] = -1; 35 } 36 for (i = 0; i < m; i++) { 37 scanf("%d%d", &j, &k); 38 edge[i].node = k; 39 edge[i].next = adj[j]; 40 adj[j] = i; 41 } 42 43 // O(VE) or O(mn) 44 for (count = 0, i = 1; i <= n; i++) { 45 dfs(i); 46 for (; top >= 0; top--) { 47 j = stack[top]; 48 instack[j] = false; 49 if (!tc[i][j]) { 50 tc[i][j] = true; 51 count++; 52 } 53 } 54 } 55 printf("%d ", n*(n-1)/2 - count); 56 return 0; 57 }