簡體   English   中英

在無向圖上查找和打印O(n)復雜度的簡單周期的算法

[英]Algorithm to find and print simple cycle in complexity of O(n) on undirected graph

給定graph G(V,E),無向圖。

|E| = m, |V| = n 

圖的數據結構是鄰接列表

如何在O(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函數不會打印所有頂點。

我需要一些幫助如何打印我發現的循環的頂點。

我注意到你的算法中有兩件似乎不正確的事情。 首先,當您使用DFS步行時,您應該保持以下不變量:

  1. 未訪問的頂點應塗成白色; (你做到了)
  2. 訪問頂點Visit()尚未結束)應該塗成灰色;
  3. 訪問過的頂點Visit()返回的頂點應該塗成黑色(或顏色,灰色或白色除外)。

我注意到的另一件事是,您沒有正確地為父節點分配節點。 在您的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);
}

在遞歸搜索中,您可以添加一個參數,該參數是一直到搜索根的祖先鏈。 循環將由當前節點和鏈中的那些節點組成,這些節點在找到循環的灰色節點處結束。

通過鏈我的意思是一個lisp風格的列表:一對由一個節點和另一對組成,最后一對是null。

更直接的方法是使用顯式堆棧而不是遞歸進行搜索。 堆棧上的節點都是灰色的。 當您發現灰色節點指示循環時,可以通過堆棧向后工作來打印循環。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM