編輯
如果兩個頂點可以相互通達,則稱兩個頂點
強連通(strongly connected)。如果
有向圖g的每兩個頂點都
強連通,稱g是乙個
強連通圖
。有向圖的極大強連通子圖,稱為
強連通分量
(strongly connected components)。
下圖中,子圖為乙個
強連通分量,因為頂點1,2,3,4兩兩可達。,也分別是兩個強連通分量。
tarjan演算法是用來求有向圖的強連通分量的。求有向圖的強連通分量的tarjan演算法是以其發明者robert tarjan命名的。robert tarjan還發明了求
雙連通分量的tarjan演算法。
tarjan演算法是基於對圖
深度優先搜尋的演算法,每個強連通分量為搜尋樹中的一棵子樹。搜尋時,把當前搜尋樹中未處理的
節點加入乙個
堆疊,回溯時可以判斷棧頂到棧中的節點是否為乙個強連通分量。
定義 dfn(u)為節點u搜尋的次序編號(
時間戳),low(u)為u或u的子樹能夠追溯到的最早的棧中節點的次序號。
當dfn(u)=low(u)時,以u為根的搜尋子樹上所有節點是乙個
強連通分量。
接下來是對演算法流程的演示。
從節點1開始dfs,把
遍歷到的節點加入棧中。搜尋到節點u=6時,
dfn[6]=low[6],找到了乙個強連通分量。退棧到u=v為止,為乙個強連通分量。
返回節點5,發現dfn[5]=low[5],退棧後為乙個
強連通分量。
堆疊。發現節點4向節點1有後向邊,節點1還在棧中,所以low[4]=1。節點6已經出棧,(4,6)是橫叉邊,返回3,(3,4)為樹枝邊,所以low[3]=low[4]=1。
繼續回到節點1,最後訪問節點2。訪問邊(2,4),4還在棧中,所以low[2]=dfn[4]=5。返回1後,發現dfn[1]=low[1],把棧中節點全部取出,組成乙個
連通分量。
至此,演算法結束。經過該演算法,求出了圖中全部的三個
強連通分量,,。
可以發現,執行tarjan演算法的過程中,每個頂點都被訪問了一次,且只進出了一次
堆疊,每條邊也只被訪問了一次,所以該演算法的
時間複雜度為o(n+m)。
#include
#include
#include
#include
#include
using
namespace
std;
const
int maxn = 5e4 + 10;
intstack[maxn]; // 每遍歷乙個點便入棧
int top;
bool instack[maxn]; // 判斷某個點是否已經在棧裡面
// 這兩個陣列至關重要
// dfn[u]為節點u搜尋的次序編號(時間戳)
// low[u]為u或者u的子樹能夠追溯到的最早的棧中節點的次序號
int dfn[maxn];
int low[maxn];
int belong[maxn]; // 判斷哪些點聯通
int bcnt, dindex; // 記錄強連通個數和當前時間
vector
v[maxn]; // 鄰接表儲存邊
int n, m, q;
void init()
return ;
}void tarjan(int u, int fa)
else
if (instack[k] && k != fa) // 被訪問過
}if (dfn[u] == low[u])
while (tmp != u);
}return ;
}void solve()
}}int main(int argc, const
char * argv)
solve();
cin >> q;
while (q--)
else
}return
0;}
51nod 1076 2條不相交的路徑
給出乙個無向圖g的頂點v和邊e。進行q次查詢,查詢從g的某個頂點v s 到另乙個頂點v t 是否存在2條不相交的路徑。兩條路徑不經過相同的邊 注,無向圖中不存在重邊,也就是說確定起點和終點,他們之間最多只有1條路 收起輸入 第1行 2個數m n,中間用空格分開,m是頂點的數量,n是邊的數量。2 m ...
51nod 1076 2條不相交的路徑(待完成)
1076 2條不相交的路徑 基準時間限制 1 秒 空間限制 131072 kb 分值 40 難度 4級演算法題 給出乙個無向圖g的頂點v和邊e。進行q次查詢,查詢從g的某個頂點v s 到另乙個頂點v t 是否存在2條不相交的路徑。兩條路徑不經過相同的邊 注,無向圖中不存在重邊,也就是說確定起點和終點...
51nod1078 3條不相交的路徑
題目 參考自洛谷p6658 這是一道三連通分量分解的模板提,具體的分析可以看洛谷的鏈結。通過分解三連通分量以後,這道題就變成了簡單的並查集問題。中的ans即三連通分量分解後的結果。大部分 自洛谷p6658的作者 這裡記錄的是三連通分量的模板 include include include inclu...