有向图G的树状结构是有根树,因此在图中存在从根到每个其他顶点的有向路径。提供一种有效且正确的算法来测试G是否包含一个树状及其时间复杂度。
我只能考虑从每个节点运行DFS / BFS,直到其中一个DFS覆盖了所有节点。 我想过使用最小生成树算法,但这也仅适用于非定向图
还有其他有效的算法吗?
我发现了一个跟进问题,其中说明有一个O(n + m)算法,任何人都可以帮助解决这个问题吗?
答案 0 :(得分:6)
您正在寻找的是所谓的Edmond算法。最小生成树算法不适用于有向图,但这是一个想法。当图表被指示并且树状结构是您在上面描述的时候,MST问题变成了树状问题。
天真的复杂性是O(EV),就像Prim的无向MST问题算法一样,但我确信它的实现速度更快。
有关详细信息,请查看Wiki页面:
答案 1 :(得分:1)
首先要注意的是,上述问题中给出的有向图的树状结构的定义与例如在Wikipedia:您的问题的定义不要求路径是唯一的,也不要求原始有向图G是加权的。因此,解决方案应该比Edmond's Algorithm处理的解决方案更简单。
以下内容如下:第一部分将是找到一个足够的根。一旦找到足够的根,从该根开始在图G上运行一个简单的DFS应该允许我们创建所需的树,我们就完成了。那么我们怎样才能找到这样的根?
首先运行DFS并“减少”发现单边的任何循环。在任何发现的循环中,无论我们使用哪个边缘,因为它们中的任何一个都可以到达任何其他边缘。如果在减少之后留下单个边缘,则意味着整个图形是强连接的,因此任何边缘 - 包括唯一的边缘 - 都可以作为根。
如果剩下多个边,则遍历所有剩余边,找到入度为零的边。如果找到多个 - 那么我们就无法构建所需的树 - 因为它们无法彼此联系。如果在这里只找到一条边 - 那就是我们的根边缘。
复杂性是O(边缘+顶点),比如说图的邻接列表表示。
答案 2 :(得分:0)
我认为这比我想象的要简单得多。在线程开头已经提到的类似行中的东西。因此,基本上使用BFS在图形中的任何节点上启动DFS遍历,并尽可能地达到,然后一旦完成。只需获取下一个未访问的顶点并再次进行BFS遍历,并且遇到已经处理的节点意味着这已经处理了子树,并且通过该节点可到达的所有节点将通过另一个节点到达节点,从而生成当前节点作为这个新子树的父级。
只需执行DFS遍历,其中每个边缘只能被访问一次。请执行以下操作
edgeCb()
{
// Already processed and has no parent means this must a sub tree
if ( g->par[ y ] == -1 && g->prc[ y ] )
g->par[ y ] = x; // Connecting two disconnected BFS/DFS trees
return 1;
}
graphTraverseDfs( g, i )
{
// Parent of each vertex is being updated as and when it is visited.
}
main() {
.
.
for ( i = 0; i < g->nv; i++ )
if ( !g->vis[ i ] )
graphTraverseDfs( g, i );
.
.
}