SCC(強連通分量)

2022-04-05 15:36:20 字數 3994 閱讀 7921

1.定義:

在有向圖g中,如果兩個頂點間至少存在一條路徑,稱兩個頂點強連通(sc---strongly connected)。

有向圖中的極大強連通子圖,成為強連通分量(scc---strongly connected components)。

下圖中,子圖為乙個強連通分量,因為頂點1,2,3,4兩兩可達,,也分別是兩個強連通分量。

2.tarjan演算法-----九野講解

tarjan演算法的基礎是dfs。我們準備兩個陣列low和dfn。low陣列是乙個標記陣列,記錄該點所在的強連通子圖所在搜尋子樹的根節點的 dfn值,dfn陣列記錄搜尋到該點的時間,也就是第幾個搜尋這個點的。根據以下幾條規則,經過搜尋遍歷該圖(無需回溯)和 對棧的操作,我們就可以得到該有向圖的強連通分量。

陣列的初始化:當首次搜尋到點p時,dfn與low陣列的值都為到該點的時間。

堆疊:每搜尋到乙個點,將它壓入棧頂。

當點p有與點p』相連時,如果此時(時間 = dfn[p]時)p』不在棧中,p的low值為兩點的low值中較小的乙個。

當點p有與點p』相連時,如果此時(時間 = dfn[p]時)p』在棧中,p的low值為p的low值和p』的dfn值中較小的乙個。

每當搜尋到乙個點經過以上操作後(也就是子樹已經全部遍歷)的low值等於dfn值,則將它以及在它之上的元素彈出棧。這些出棧的元素組成乙個強連通分量。

///

其時間複雜度也是o(n+m)

#include #include

#include

#include

#include

using

namespace

std;

#define n 10005 //

/ 題目中可能的最大點數

stack

sta; ///

儲存已遍歷的結點

vectorgra[n]; ///

鄰接表表示圖

int dfn[n]; ///

深度優先搜尋訪問次序

int low[n]; ///

能追溯到的最早的次序

intinstack[n];

///檢查是否在棧中(2:在棧中,1:已訪問,且不在棧中,0:不在)

vector component[n]; ///

獲得強連通分量結果

int incomponent[n]; ///

記錄每個點在第幾號強連通分量裡

int index,componentnumber;///

索引號,強連通分量個數

int n, m; ///

點數,邊數

void init()///

清空容器,陣列

while(!sta.empty())

sta.pop();

}void tarjan(int

u)

else

if (instack[t] == 2)///

在棧裡 }

if(low[u] == dfn[u])///

sta出棧就是乙個強連通分量的

}}void input(void)}

void solve(void

)int

main()

return0;

}

hdu1269也能做模板

1

///時間複雜度為o(n+m)

2///呼叫3

///1、init()

4///

2、把圖用add 存下來,注意圖點標為1-n,若是[0,n-1]則給所有點++;

5///

3、呼叫tarjan_init(n); 再呼叫suodian();

6///

4、新圖就是vector

g; 新圖點標從1-tar ;

7///

5、對於原圖中的每個點u,都屬於新圖中的乙個新點belong[u];

8///

新圖一定是森林。

9///

6、新圖中的點u 所表示的環對應原圖中的vector

bcc[u];

10///

7、舊圖中u在新圖中所屬的點是belong[u];

11 #include 12 #include 13 #include 14 #include 15 #include 16 #include 17

#define repu(i, a, b) for(int i = a; i < b; i++)

18using

namespace

std;

19#define n 30100

20///

n為最大點數

21#define m 150100

22///

m為最大邊數

23int n, m;///

n m 為點數和邊數

2425

struct

edge

26 edge[m<<1

];30

31int

head[n], edgenum;

3233

void add(int u, int v) ///

邊的起點和終點34;

36 edge[edgenum] =e;

37 head[u] = edgenum++;38}

3940

intdfn[n], low[n], stack[n], top, time;

41///

low[u]是點集 中(所有反向弧)能指向的(離根最近的祖先v) 的dfn[v]值(即v點時間戳)

42int taj;///

連通分支標號,從1開始

43int belong[n];///

belong[i] 表示i點屬於的連通分支

44bool

instack[n];

45 vector bcc[n]; ///

標號從1開始

4647

void tarjan(int u ,int

fa)48

62else

if(instack[v])

63 low[u] =min(low[u] ,dfn[v]) ;64}

65if(low[u] == dfn[u])///

找到乙個強連通分量

6677

while(now !=u) ;78}

79}8081

void tarjan_init(int

all)

8291

92 vectorg[n];

93int

du[n];

94void

suodian()

95105

}106

107void

init()

108112

113int

main()

114124

tarjan_init(n);

125//

repu(i,1,taj + 1)

///輸出每乙個強連通分量

126//

131if(taj > 1

)132 printf("

no\n");

133else

134 printf("

yes\n");

135}

136return0;

137 }

九野模板--hdu1269

參考鏈結

強連通分量SCC

poj2762 題意 給出n個點,對於每個點,如果任意選擇兩點s,e,都滿足s可以到達e或者e可以到達s,則輸出yes,否則輸出no。用了白書裡的模板 參考解決思路是 首先求出原圖g的強連通分量並且縮點,求出縮點後的圖mat,並且求出縮點後所有頂點的入度in。這時我們思考下,如果原圖g要是半連通的,...

強連通分量(SCC)模版

如題,模版如下 scc cnt為scc計數器,sccno i 為i所在的scc編號 scc cnt為scc個數,scc的 編號從1開始 vector g maxn 圖存在g maxn 中,若有一條從v u的邊,則儲存時先v u 再g v push back u 即結點從0開始編號 int pre m...

kosaraju求scc 強連通分量

題目要求 大學班級選班長,n 個同學均可以發表意見 若意見為 a b 則表示 a 認為 b 合適,意見具有傳遞性,即 a 認為 b 合適,b 認為 c 合適,則 a 也認為 c 合適 勤勞的 tt 收集了m條意見,想要知道最高票數,並給出乙份候選人名單,即所有得票最多的同學,你能幫幫他嗎?input...