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值,則將它以及在它之上的元素彈出棧。這些出棧的元素組成乙個強連通分量。
///hdu1269也能做模板其時間複雜度也是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;
}
1九野模板--hdu1269///時間複雜度為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 }
參考鏈結
強連通分量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...