DFS應用:圖的拓撲排序以及Kosaraju強連通分量算法

圖的DFS算法對於每一個圖節點u有2個重要的時間d[u]和f[u],分別代表找到u的時間(其變爲灰色節點的時間)以及u完成的時間(其變爲黑色節點的時間).
f[u]越大可能其在最上面(樹根處),所以要等其所有子孫都完成其才能完成.

1、拓撲排序

對於一個圖,找拓撲排序的方法就是通過按照完成時間f[u]的遞減順序即爲一個拓撲排序:

void graph::topology(int start,queue<int> &tpmap)
{
    int Pnum = this->Pnum;
    int visit[1000];
    memset(visit, 0, sizeof(visit));
    stack<int> s;
loop:   s.push(start);
    visit[start] = 1;
    int step;
    int h = 0;
    while (!s.empty())
    {
        int find = 0;
        int p = s.top();
        for (int i = 0; i < Pnum; i++)
        {
            if (!visit[i] && edge[p][i] != INF)
            {
                find = 1;
                s.push(i);
                visit[i] = 1;
                h++;
            }
        }
        if (!find)
        {
            int temp = s.top();
            s.pop();
            tpmap.push(temp);
            h--;
        }
    }
    for (int i = 0; i < Pnum; i++)
        if (!visit[i])
        {
            start = i;
            goto loop;
        }

    for (int i = 0; i < Pnum; i++)//將隊列元素顛倒
    {
        s.push(tpmap.front());
        tpmap.pop();
    }
    for (int i = 0; i < Pnum; i++)
    {
        tpmap.push(s.top());
        s.pop();
    }
}

2、Kosaraju算法

此法用了2此DFS,第一次在原圖,第二次在其轉置圖,此算法主要利用下面定理:
原圖的DFS完成時間晚的連通分量,其在轉置圖中不會有邊指向在原圖DFS時完成時間早的連通分量.

算法:
step1:對原圖G進行深度優先遍歷,記錄每個節點的離開時間。
step2:選擇具有最晚離開時間的頂點,對反圖GT進行遍歷,刪除能夠遍歷到的頂點,這些頂點構成一個強連通分量。
step3:如果還有頂點沒有刪除,繼續step2,否則算法結束。

void graph::strongly_connected_conponets(int start)
{
    queue<int> tpmap;
    topology(start, tpmap);//step1
    graph reverse_g;
    for (int i = 0; i < Pnum; i++)//step2、構造圖G的轉置圖
        for (int j = 0; j < Pnum; j++)
        {
            if (edge[i][j])
                reverse_g.edge[j][i] = edge[i][j];
        }
    int visit[100];
    memset(visit, 0, sizeof(visit));
    stack<int> s;
    while (!tpmap.empty())//step3
    {

        if (!visit[tpmap.front()])
        {
            s.push(tpmap.front());
            visit[tpmap.front()] = 1;
            tpmap.pop();
        }
        else
        {
            tpmap.pop();
            continue;
        }
        while (!s.empty())//每棵樹都完成了即爲一個連通分量
        {
            int find = 0;
            int now_point = s.top();
            for (int i = 0; i < Pnum; i++)
            {
                if (reverse_g.edge[now_point][i] != INF && !visit[i])
                {
                    find = 1;
                    s.push(i);
                    visit[i] = 1;
                }
            }
            if (!find)
            {
                cout << now_point;
                s.pop();
            }
        }
        cout << endl;
    }
}
發佈了34 篇原創文章 · 獲贊 12 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章