poj-1236–一起學習強連通分量2

來源:互聯網
上載者:User

上一篇介紹過題目大意和kosaraju演算法

本篇介紹tarjan演算法。

引用一下講解:

 

概述

此演算法以一個有向圖作為輸入,並按照所在的強連通分量給出其頂點集的一個劃分。圖中的每個結點只在一個強連通分量中出現,即使是在有些結點單獨構成一個強連通分量的情況下(比中出現了樹形結構或孤立結點)。

演算法的基本思想如下:任選一結點開始進行深度優先搜尋(若深度優先搜尋結束後仍有未訪問的結點,則再從中任選一點再次進行)。搜尋過程中已訪問的結點不再訪問。搜尋樹的若干子樹構成了圖的強連通分量。

結點按照被訪問的順序存入棧中。從搜尋樹的子樹返回至一個結點時,檢查該結點是否是某一強連通分量的根結點(見下)並將其從棧中刪除。如果某結點是強連通分量的根,則在它之前出棧且還不屬於其他強連通分量的結點構成了該結點所在的強連通分量。

根結點的性質

演算法的關鍵在於如何判定某結點是否是強連通分量的根。注意“強連通分量的根”這一說法僅針對此演算法,事實上強連通分量是沒有特定的“根”的。在這雷根結點指深度優先搜尋時強連通分量中首個被訪問的結點。

為找到根結點,我們給每個結點v一個深度優先搜尋標號v.index,表示它是第幾個被訪問的結點。此外,每個結點v還有一個值v.lowlink,表示從v出發經有向邊可到達的所有結點中最小的index。顯然v.lowlink總是不大於v.index,且當從v出發經有向邊不能到達其他結點時,這兩個值相等。v.lowlink在深度優先搜尋的過程中求得,v是強連通分量的根若且唯若v.lowlink
= v.index。

虛擬碼
algorithm tarjan is  input:G = (V, E)  output: 以所在的強連通分量劃分的頂點集  index := 0  S := empty    // 置棧為空白  for each v in V do    if (v.index is undefined)      strongconnect(v)    end if  function strongconnect(v)    // 將未使用的最小index值作為結點v的index    v.index := index    v.lowlink := index    index := index + 1    S.push(v)    // 考慮v的後繼結點    for each (v, w) in E do      if (w.index is undefined) then        // 後繼結點w未訪問,遞迴調用        strongconnect(w)        v.lowlink := min(v.lowlink, w.lowlink)      else if (w is in S) then        // w已在棧S中,亦即在當前強連通分量中        v.lowlink := min(v.lowlink, w.index)      end if    // 若v是根則出棧,並求得一個強連通分量    if (v.lowlink = v.index) then      start a new strongly connected component      repeat        w := S.pop()        add w to current strongly connected component      until (w = v)      output the current strongly connected component    end if  end function

變數index是深度優先搜尋的結點計數器。S是棧,初始為空白,用於儲存已經訪問但未被判定屬於任一強連通分量的結點。注意這並非一個一般深度優先搜尋的棧,結點不是在以它為根的子樹搜尋完成後出棧,而是在整個強連通分量被找到時。

最外層迴圈用於尋找未訪問的結點,以保證所有結點最終都會被訪問。strongconnect進行一次深度優先搜尋,並找到結點v的後繼結點構成的子圖中所有的強連通分量。

當一個結點完成遞迴時,若它的lowlink仍等於index,那麼它就是強連通分量的根。演算法將在此結點之後入棧(包含此結點)且仍在棧中的結點出棧,並作為一個強連通分量輸出。

備忘
  1. 複雜度:對每個結點,過程strongconnect只被調用一次;整個程式中每條邊最多被考慮兩次。因此演算法的已耗用時間關於圖的邊數是線性,即。
  2. 判斷結點v'是否在棧中應在常數時間內完成,例如可以對每個結點儲存一個是否在棧中的標記。
  3. 同一個強連通分量內的結點是無序的,但此演算法具有如下性質:每個強連通分量都是在它的所有後繼強連通分量被求出之後求得的。因此,如果將同一強連通分量收縮為一個結點而構成一個有向非循環圖,這些強連通分量被求出的順序是這一新圖的拓撲序的逆序[2]。

代碼:

 

#include <stdio.h>#include <stdlib.h>#include <string.h>#define nMax 110#define Min(x,y) (x<y?x:y)int map[nMax][nMax];int belong[nMax];int DFN[nMax],Low[nMax],stack[nMax];bool inStack[nMax];int n,index,cnt,top;int indegree[nMax],outdegree[nMax];void tarjan(int u)//tarjan演算法{DFN[u] = Low[u] = ++index;//時間戳記及low的初始化stack[top ++] = u;//堆棧inStack[u] = true;//是否已經在棧中for (int i = 1; i <= n; ++ i){if (map[u][i])//如果有邊{if (!DFN[i])//如果還沒訪問過{tarjan(i);Low[u] = Min(Low[u], Low[i]);}else if (inStack[i])//如果已經在堆棧中{Low[u] = Min(Low[u], DFN[i]);}}}if (DFN[u] == Low[u])//強連通分量{cnt ++;while (1){int tmp = stack[-- top];belong[tmp] = cnt;//記錄屬於cnt強連通分量的所有點tmpinStack[tmp] = false;//並出棧if (tmp == u)//到達根節點{break;}}}}void output(){int inNum = 0,outNum = 0;memset(indegree, 0, sizeof(indegree));memset(outdegree, 0, sizeof(outdegree));for (int i = 1; i <= n; ++ i)//求強連通分量的出度和入度{for (int j = 1; j <= n; ++ j){if (map[i][j] && belong[i] != belong[j]){indegree[belong[j]] ++;outdegree[belong[i]] ++;}}}for (int i = 1; i <= cnt; ++ i)//求出出度和入度為0的點的個數{if (!indegree[i]){inNum ++;}if (!outdegree[i]){outNum ++;}}if (cnt == 1)//如果這個圖強連通{printf("1\n0\n");}else//否則printf("%d\n%d\n",inNum, inNum > outNum ? inNum : outNum);}int main(){while (scanf("%d", &n) != EOF){memset(map, 0, sizeof(map));memset(inStack, false, sizeof(inStack));memset(DFN, 0, sizeof(DFN));index = cnt = top = 0;for (int i = 1; i <= n; ++ i){int v;while (scanf("%d", &v) && v){map[i][v] = 1;}}for (int i = 1; i <= n; ++ i){if (!DFN[i]){tarjan(i);//tarjan演算法}}output();}return 0;}

 

 

 

雖然看了好多文章,理解了好多遍,但是在下還有一點不明白,忘大神指點一二:

就是求Low[u]的時候,為何不全是Min(Low[u], Low[i])為何還有在不在棧中之分???????????求解釋。

最主要的是將Min(Low[u], DFN[i])改為Min(Low[u], Low[i])程式也能過,我相信這個地方肯定是有用的,也許我還沒學習到吧。。。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.