当前位置: 首页 > 知识库问答 >
问题:

使用DFS检查无向图中的循环?

齐胜涝
2023-03-14

因此,我为DFS编写了以下代码:

void dfs (graph * mygraph, int foo, bool arr[]) // here, foo is the source vertex
{
    if (arr[foo] == true)
        return;
    else
    {
        cout<<foo<<"\t";
        arr[foo] = true;
        auto it = mygraph->edges[foo].begin();
        while (it != mygraph->edges[foo].end())
        {
            int k = *it;
            if (arr[k] == false)
            {
                //cout<<k<<"\n";
                dfs(mygraph,k,arr);
                //cout<<k<<"\t";
            }
            it++;
        }
    }
    //cout<<"\n";
}

现在,我读到,在一个无向图中,如果当DFS时,它再次返回到同一个顶点,有一个循环。所以我做的是这样,,

bool checkcycle( graph * mygraph, int foo, bool arr[] )
{

    bool result = false;
    if (arr[foo] == true)
    {
        result = true;
    }
    else
    {
        arr[foo] = true;
        auto it = mygraph->edges[foo].begin();
        while (it != mygraph->edges[foo].end())
        {
            int k = *it;
            result = checkcycle(mygraph,k,arr);     
            it++;
        }
    }
    return result;
}   

但是,我的检查周期函数返回true,即使他们没有周期。那是为什么呢?我的功能有问题吗?没有执行问题,否则我早就调试了,但他们似乎在我的逻辑中有问题。

共有2个答案

夏祺然
2023-03-14

在检查周期开始之前,arr[]中的所有bools都设置为false吗?

您确定节点的迭代器没有在已经遍历的边上加倍(从而多次看到起始节点,而不考虑循环)?

韦欣德
2023-03-14

请注意,您的函数并不像您认为的那样。让我来看看这里发生了什么。假设以下关系:(1,2)、(1,3)、(2,3)。我并没有假设反射性(即,(1,2)并不意味着(2,1))。关系是定向的。

  1. 从节点1开始。将其标记为已访问

您需要一堆已访问的节点,或者只搜索原始节点。堆栈也将检测子循环(不包括原始节点的循环),但它也会占用更多内存。

编辑:节点堆栈不仅仅是一堆true/false值,而是节点编号的堆栈。当前堆栈跟踪中已访问的节点(如果该节点存在于堆栈中)。

然而,还有一种更有利于内存的方法:在调用结束时设置arr[foo]=false;。像这样的东西:

bool checkcycle( graph * mygraph, int foo, bool arr[], int previousFoo=-1 )
{
    bool result = false;
    if (arr[foo] == true)
    {
        result = true;
    }
    else
    {
        arr[foo] = true;
        auto it = mygraph->edges[foo].begin();
        while (it != mygraph->edges[foo].end())
        {
            int k = *it;

            // This should prevent going back to the previous node
            if (k != previousFoo) {
                result = checkcycle(mygraph,k,arr, foo);
            }

            it++;
        }
        
        // Add this
        arr[foo] = false;
    }
    return result;
}   

我想应该够了。

编辑:现在应该支持无向图。节点:此代码未测试

编辑:有关详细的解决方案,请参见强连接组件

编辑:尽管在评论中给出了具体的解决方案,但这个答案是市场所接受的。阅读评论了解详细信息。

 类似资料:
  • 请告诉我为什么这段代码不能分析无向图中是否有循环?代码如下。这是Spoj上的PT07Y问题。我正在做的是取一个节点并执行dfs。当执行dfs时,如果我访问同一个节点,那么我说有一个循环。从一个节点执行dfs后,我使访问的数组为假,并为下一个节点执行,直到我得到一个周期或所有节点都被访问。

  • 另一个问题只回答了如何检测一个周期,而不是输出它。所以,我想在一个无向图上写一个算法,在O(V+E)时间内运行BFS或DFS(V=顶点,E=边),如果有循环,则输出循环。 到目前为止,我所知道的是BFS/DFS是如何工作的,如果访问已经标记为已访问的节点,可以使用BFS检测周期。

  • 目前我正在用这个样本进行拓扑排序,并对https://www.geeksforgeeks.org/topological-sorting/做了一些修改 我用它来排序要求解的变量的顺序。 样本 每个变量都有一个唯一整数,并存储在一个映射中 创建图形并添加边时,总共有4个顶点,因此我的代码将像这样构造图形 排序并按相反顺序得到结果后,它是正确的c 一切都很好,但我需要检测图中的循环引用。假设变量是 有

  • 我有一个带边的无向图。每条边都具有一定的性质,如A点和B点之间的边之一是 在C点和D点之间的另一个可以是 我们得到了这样一个图和已知的旅行路径 有快一点的吗?

  • 假设我有一个有V节点和E边的无向图。如果我用邻接列表表示图形,如果我有x和y之间边的表示,我还必须在邻接列表中有y和x之间边的表示。 我知道有向图的DFS具有VE复杂性。对于无向图,它没有v 2*e复杂性,因为您访问每个边2次?抱歉,如果这是一个愚蠢的问题...我真的很想明白这个想法。谢谢你,

  • 我看到了这篇SO帖子,其中建议在有向图中使用DFS进行循环检测由于回溯而更快。这里我引用该链接: 深度优先搜索比广度优先搜索更节省内存,因为您可以更快地回溯。如果使用调用堆栈,则实现起来也更容易,但这取决于不溢出堆栈的最长路径。 如果你的图是有方向的,那么你不仅要记住你是否访问过一个节点,还要记住你是如何到达的。否则,你可能会认为你已经找到了一个循环,但在现实中,你所拥有的只是两条不同的路径- 为