日常補東西 這次是tarjan演算法 原理還是別翻我這裡了......但其他的倒是挺詳細的~~
先給個題目 見下
題目大意:n (2 ≤ n ≤ 10000) 個點,m (2 ≤ m ≤ 50000) 條邊 求大於1的強連通分量的個數
好了tarjan演算法走起
tarjan 演算法最主要的還是兩個陣列
dfn 用來表示當前點的dfs序編號 (同樹剖那個id) 就是記錄當前點是第幾個被遍歷到的
low 則表示當前點所在強連通分量的 ' 根 ' 就是該強連通分量的點中編號最小的那個 主要用途就是當 dfn[p] == low[p] 時說明該強連通分量搜完了 然後存下來
還有乙個陣列 (我個人叫他from) 用來存某點所在的強連通分量的編號 但本題用不到 這個更新...放在彈出棧的迴圈裡
說到遍歷的話 這裡用棧(stack然而我嫌名字太長用que代替) 每搜到乙個點就丟進去
如何遍歷呢
先把最重要的 dfn 和 low 的 值賦了 一開始 low 的值 等於遍歷的這個點的 dfn 值
因為乙個點的 dfn 值 等於其 low 值 的時候 說明這是乙個強連通分量的根(開始的時候是一樣的 就是把每個點都當成乙個強連通分量 之後再去搜尋 合併)
然後我們進行dfs深度優先搜尋 等到搜到之前的點了 說明此時的點就可以更新到之前某處的點 於是回溯之後該點的上乙個點 上兩個點 上三個點......搜到那個點了 就都能連到一塊了 這樣乙個大的強連通分量就出來了
如果搜到最後沒點繼續往下走了 都散了散了 這裡沒有大於一的強連通分量
但所有的點都要搜到哇 沒搜到的點的話還要繼續哇 tarjan 在不一定完全連通的圖裡面也是要用到的
於是用乙個日常的 o 陣列 判斷是否找過 沒找過就從那個點開始 tarjan 即可
遍歷完了怎麼辦? 開始彈出該強連通分量的所有點 當然別忘了彈出根 建議用 do{} while() 然而我是用 while() 外面再加一次的
2018.12.15 update : 打仙人掌的時候發現無向圖用 tarjan 的時候要判父親不能回去 有向圖無向圖區別就這個
之後根據題目所需自己瞎搞搞就好 本題**放下來 鏈結這裡再放乙個
#include using namespace std;
const int maxn = 10010;
const int maxm = 100010;
struct edge e[maxm];
int first[maxn],dfn[maxn],low[maxn],que[maxn],num[maxn]/*,id[maxn]*/;
int g,tot,t;
short o[maxn];
int min(int x,int y)
void add(int x,int y)
void tarjan(int p)
if (dfn[p] == low[p]) //找到強連通分量的根了!然而有可能是單個點= = }
int main()
強連通分量 tarjan求強連通分量
雙dfs方法就是正dfs掃一遍,然後將邊反向dfs掃一遍。挑戰程式設計 上有說明。雙dfs 1 include 2 include 3 include 4 include 5 6using namespace std 7const int maxn 1e4 5 8 vector g maxn 圖的鄰...
強連通分量 tarjan
洛谷 p2812 校園網路 洛谷 p3387 縮點 include include include include include using namespace std struct arrbot 1100000 d 1100000 int head 20000 h 20000 stack 200...
強連通分量 tarjan
struct enodeedge maxm int p maxn ec void inserte int u,int v,int w int dfn maxn ctime,low maxn 時間戳,時間戳計數,祖先時間。int gid maxn gc 分量陣列,分量計數。bool ins maxn ...