雙dfs方法就是正dfs掃一遍,然後將邊反向dfs掃一遍。《挑戰程式設計》上有說明。
雙dfs**:
1 #include 2 #include 3 #include 4 #include 56using
namespace
std;
7const
int maxn = 1e4 + 5
;8 vector g[maxn]; //
圖的鄰接表
9 vector rg[maxn]; //
圖的反向鄰接表
10 vector vs; //
後序遍歷的頂點順序表
11bool ok[maxn]; //
訪問標記
12int node[maxn]; //
所屬強連通分量的序號
13//
第一次dfs
14void dfs(int
u) 20
vs.push_back(u);21}
22//
第二次dfs
23void rdfs(int u , int
k) 30}31
32int
main()
3342
for(int i = 0 ; i < m ; i++)
47//
第一次dfs 選取任意的頂點作為起點遍歷 後序遍歷 越接近圖尾部(葉子)的頂點順序越小
48for(int i = 1 ; i <= n ; i++)
52 memset(ok , false , sizeof
(ok));
53int k = 0;54
//第二次dfs 將邊反向遍歷 以標記最大的頂點作為起點遍歷 這樣便可以給強連通分量標號
55for(int i = vs.size() - 1 ; i >= 0 ; i--)
59if(k > 1
) 62
else65}
66 }
tarjan**雖然比雙dfs多,理解也稍微複雜,但是用處比較多,像求lca 橋 scc之類的問題。
推薦乙個學scc的blog,講的很好。
**如下:
1//以hdu1269為例2//
強連通分量 tarjan演算法
3 #include 4 #include 5 #include 6 #include 7
using
namespace
std;
8const
int maxn = 1e4 + 5
;9 vector g[maxn]; //
臨接表10
bool instack[maxn]; //
i是否還在在棧裡
11int sccnum , index; //
連通分量數 和時間順序
12int top , st[maxn]; //
儲存i的模擬棧
13int block[maxn]; //
i所屬的連通分量
14int low[maxn] , dfn[maxn]; //
i能最早訪問到的點 和時間戳
1516
void tarjan(int
u) 27}28
else
if(instack[v]) 31}
32int
v;33
if(dfn[u] == low[u]) while(v != u); //
連通分量的所有的點40}
41}4243
void init(int
n) 49 sccnum = index = top = 0;50
}5152int
main()
5361
for(int i = 1 ; i <= n ; i++) 65}
66if(sccnum > 1
) 69
else72}
73 }
Tarjan求強連通分量
強連通分量 有向圖強連通分量 在有向圖g中,如果兩個頂點間至少存在一條路徑,稱兩個頂點強連通 strongly connected 如果有向圖g的每兩個頂點都強連通,則稱g是乙個強連通圖。非強連通圖有向圖的極大強連通子圖,成為強連通分量 strongly connected components 直...
tarjan求強連通分量
tarjan求強連通分量 我們知道,在有向圖g中,如果任意兩個頂點都是連通的 所謂連通就是兩個頂點都能互相到達 那麼這個圖就是強連通圖。非強連通圖的極大強連通子圖,被稱為強連通分量。那麼什麼是極大強連通子圖呢?舉個例子幫助理解一下 例如下面圖一所示,其中子圖就是乙個極大強連通子圖,子圖也是乙個極大強...
Tarjan求強連通分量
強連通分量可以用tarjan求 比兩遍dfn大概快30 定義乙個棧 把點壓進去,然後根據自己所能到的點,求出能到達的dfn序最小的點 由此得到從此點到low點中的點 在棧中 可以成為乙個強連通分量 具體實現是當x點滿足dfn low時,將棧中的點全部彈出至x點 可以證明每個點最多被彈出1次,每條邊最...