我不完全确定这是否正确,但我认为检查有向图是否“连接”就足够了(请参阅下面的算法描述以了解我所说的连接的意思)。如果有向图中有多个连通分量,则它不是单边的。
证明尝试:
假设有向图有多个连通分量。为简单起见,让连接组件的数量为 2,我们将组件称为 C1 和 C2。从C1 中选择任意顶点v,从C2 中选择任意顶点w。由于它们在不同的连接组件中,所以从v 到w 或w 到v 没有路径,否则C1 和C2 将在同一个组件中。
对于另一种情况,假设有向图是连接的。那么对于有向图中的任意 2 个不同的顶点 x 和 y,要么存在从 x 到 y 或从 y 到 x 的路径,否则它们将不在同一个组件中。我知道这里有点手摇,但我并不擅长打样。
编辑:更简单的算法:
我确实认为修改后的深度优先搜索 / 广度优先搜索应该可以做到。本质上,我们可以从 any 顶点开始搜索。我们将从第一个顶点到达的所有顶点标记为已访问。然后遍历所有顶点。对于任何未访问的顶点,我们进行 BFS / DFS,并使用列表来跟踪我们遍历过的所有未访问的顶点。如果在 BFS/DFS 期间,我们没有从先前的 BFS/DFS 访问任何先前访问过的顶点,那么我们可以立即得出结论,有向图具有多个连通分量并且不是单边的。否则,我们将搜索过程中获得的列表中的所有顶点标记为已访问,然后继续。
一旦我们遍历了图中的所有顶点,所有 BFS / DFS 都命中了一些以前访问过的顶点,我们可以得出结论,该图是单边的。
一些伪代码来说明这一点。我将使用深度优先搜索:
// a boolean array to keep track if a given vertex is visited
// initially this is set to false
boolean[] visited
// boolean array to keep track of visited vertices for 2nd dfs onwards
boolean[] visited_two
// used for first dfs
dfs(vertex) {
visited[vertex] <- true
for each edge leading out of vertex {
dfs(next vertex)
}
}
// used for subsequent dfs
dfs_two(vertex, list_for_storing_vertices) {
// we use the visited_two array here, because the
// visited array is used to store previously visited
// vertices
visited_two[vertex] <- true
list_for_storing_vertices.append(vertex)
// return value. we return true if we encounter
// a previously visited vertex. otherwise, return false
return_value <- false
for each edge leading out of vertex {
if visited[next vertex]
return_value <- true
else if !visited_two[next_vertex]
r = dfs_two(next vertex, list_for_storing_vertices)
return_value = return_value || r
}
return return_value
}
// overall algorithm
// Returns true if the graph is unilateral. false otherwise
bool digraph_unilateral(graph) {
// Just pick any vertex. we will pick vertex 0
set all entries in `visited` array to false
dfs(0)
// then loop through all vertices. if they haven't been visited,
// we perform a dfs
for each vertex in the digraph {
if !visited[vertex] {
// reset visited_two array
set all entries in `visited_two` array to false
visited_list <- []
encountered_previously_visited <- dfs_two(vertex, visited_list)
if encountered_previously_visited {
// mark the vertices we encountered as visited
for each v in visited_list {
visited[v] <- true
}
} else {
// we did not encounter any previously visited vertex
// so all vertices we encounter on this search are in
// a distinct connected component
return false
}
}
}
return true
}
原始的、更难的算法:
我们如何计算一个有向图是否是单边的?您可以先运行Tarjan's Strongly Connected Components algorithm 并确定有向图的强连通分量。您将需要稍微修改算法以将强连接组件压缩为超顶点。这并不难做到,只需为同一个强连通分量中的每个顶点分配一个整数标签即可。换句话说,同一个强连通分量中的所有顶点都将被1个超顶点替换。 Tarjan 的 SCC(强连通分量)算法在 O(V+E) 时间运行。
在上述步骤之后,有向图现在是无环(无环)。这使我们可以继续下一步。
之后,对上面的结果图执行拓扑排序。这应该给我们一个有向无环图的拓扑排序。此步骤也使用深度优先搜索实现在O(V+E) 时间运行。
现在我们有了拓扑排序,根据拓扑排序执行广度优先搜索或深度优先搜索 >有向无环图在 Tarjan 的 SCC 步骤之后获得。如果连通分量的数量为 1,则原始图是单边的(如果连通分量的数量为 0,它也是单边的,但那是一个空图,因此是微不足道的)。否则,有多个分量,原图不是单边的。这一步也在O(V+E)时间运行。
因此,整个算法运行在O(V+E)时间。
结论
我认为这应该是正确的,但您可能想与其他人验证这种方法。如果您在理解我的方法或实现算法方面有任何困难,请发表评论。
希望有帮助!