在无向图上查找和打印O(n)复杂度的简单周期的算法

时间:2014-08-16 14:04:31

标签: algorithm graph-algorithm depth-first-search

给定graph G(V,E),无方向图。

|E| = m, |V| = n 

图表的数据结构是邻接列表

如何在O(n)的复杂程度中找到并打印简单周期(或打印没有这样的周期)? (如果存在循环,则输出应该是作为循环一部分的顶点列表。)

我知道如何找到O(n)的复杂性的循环,互联网上也有gudies 我的问题是如何打印它。

这就是我试图做的事情:

DFS-CheckCycle ( Graph G)
{
    p[] <- null //parent array
    foreach v in V
        Color[u] <- white

    foreach v in V
    {
        if (Color[u] = white) 
            Visit(u)
    }
}

Visit(Vertex u)
{
    bool Cycle <- false;
    Color[u] <- gray
    foreach v in Adj[u]
    {
        p[v] <- u
        if (Color[v] = white)
            Visit(v);
        else if (Color[v] = gray) 
        {
            Cycle <- true;
            break;
        }
    }

    if(!Cycle)
        print "No Cycle"
    else
        PrintCycle(v,u)
}



PrintCycle(Vertex v, Vertex u)
{
    if(v = u)
        print v;
    else
    {
        print v;
        PrintCycle(p[v], u);
    }
}

请记住它必须是O(n) 我的PrintCycle函数不打印所有顶点。

我需要一些帮助来打印我找到的循环的顶点。

2 个答案:

答案 0 :(得分:5)

我注意到你的算法中有两件似乎不正确的事情。首先,当您使用DFS步行时,您应该保持以下不变量:

  1. 未访问的顶点应涂成白色; (你这样做了)
  2. Visit()尚未结束的访问顶点应该涂成灰色;
  3. Visit()返回的已访问顶点应涂成黑色(或颜色,灰色或白色除外)。
  4. 我注意到的另一件事是,你没有正确地为父节点分配节点。在你的Visit()方法中,即使我们想要在下一步中访问的顶点是灰色的,即已经在DFS树中有父节点,也会分配父节点。

    所以我会相应地更改你的代码:

    DFS-CheckCycle ( Graph G)
    {
        p[] <- null //parent array
        foreach v in V
            Color[v] <- white
    
        foreach u in V
        {
            if (Color[u] = white) {
                p[u] <- -1; // meaning it is a root of a DFS-tree of the DFS forest
                Visit(u)
            }
        }
    }
    
    Visit(Vertex u)
    {
        bool Cycle <- false;
        Color[u] <- gray
        foreach v in Adj[u]
        {
            if (Color[v] = white) {
                p[v] <- u
                Visit(v);
            }
            else if (Color[v] = gray) 
            {
                Cycle <- true;
                break;
            }
        }
        Color[u] <- black; // once DFS for this vertex ends, assign its color to black
    
        if(!Cycle)
            print "No Cycle"
        else
            PrintCycle(v,u)
    }
    
    
    
    PrintCycle(Vertex v, Vertex u)
    {
        if(v = u)
            print v;
        else
        {
            print v;
            PrintCycle(p[v], u);
        }
    }
    

    编辑:将PrintCycle方法转换为非递归方法可能是个好主意:

    PrintCycle(Vertex v, Vertex u) 
    {
        do {
            print u;
            u = p[u];
        } while (u != v);
    }
    

答案 1 :(得分:0)

在递归搜索中,您可以添加一个参数,该参数是祖先的链,一直到搜索根。循环将由当前节点和链中的那些节点组成,这些节点在找到循环的灰色节点处结束。

通过链我的意思是一个lisp风格的列表:一对由一个节点和另一对组成,最后一对是空的。

更简单的方法是使用显式堆栈而不是递归进行搜索。堆栈上的节点都是灰色的。当您发现灰色节点指示循环时,可以通过堆栈向后工作来打印循环。