Tarjan 演算法&模板
Tarjan 演算法
一.演算法簡介
Tarjan 演算法一種由Robert Tarjan提出的求解有向圖強連通分量的演算法,它能做到線性時間的複雜度。
我們定義:
如果兩個頂點可以相互通達,則稱兩個頂點強連通(strongly connected)。如果有向圖G的每兩個頂點都強連通,稱G是一個強連通圖。有向圖的極大強連通子圖,稱為強連通分量(strongly connected components)。
例如:在上圖中,{1 , 2 , 3 , 4 } , { 5 } , { 6 } 三個區域可以相互連通,稱為這個圖的強連通分量。
Tarjan演算法是基於對圖深度優先搜尋
再Tarjan演算法中,有如下定義。
DFN[ i ] : 在DFS中該節點被搜尋的次序(時間戳)
LOW[ i ] : 為i或i的子樹能夠追溯到的最早的棧中節點的次序號
當DFN[ i ]==LOW[ i ]時,為i或i的子樹可以構成一個強連通分量。
二.演算法圖示
以1為Tarjan 演算法的起始點,如圖
順次DFS搜到節點6
回溯時發現LOW[ 5 ]==DFN[ 5 ] , LOW[ 6 ]==DFN[ 6 ] ,則{ 5 } , { 6 } 為兩個強連通分量。回溯至3節點,拓展節點4.
拓展節點1 , 發現1再棧中更新LOW[ 4 ],LOW[ 3 ] 的值為1
回溯節點1,拓展節點2
自此,Tarjan Algorithm 結束,{1 , 2 , 3 , 4 } , { 5 } , { 6 } 為圖中的三個強連通分量。
不難發現,Tarjan Algorithm 的時間複雜度為O(E+V).
三.演算法模板
1 void Tarjan ( int x ) { 2 dfn[ x ] = ++dfs_num ; 3 low[ x ] = dfs_num ; 4 vis [ x ] = true;//是否在棧中 5 stack [ ++top ] = x ; 6 for ( int i=head[ x ] ; i!=0 ; i=e[i].next ){ 7 int temp = e[ i ].to ; 8 if ( !dfn[ temp ] ){ 9 Tarjan ( temp ) ; 10 low[ x ] = gmin ( low[ x ] , low[ temp ] ) ; 11 } 12 else if ( vis[ temp ])low[ x ] = gmin ( low[ x ] , dfn[ temp ] ) ; 13 } 14 if ( dfn[ x ]==low[ x ] ) {//構成強連通分量 15 vis[ x ] = false ; 16 color[ x ] = ++col_num ;//染色 17 while ( stack[ top ] != x ) {//清空 18 color [stack[ top ]] = col_num ; 19 vis [ stack[ top-- ] ] = false ; 20 } 21 top -- ; 22 } 23 }
(完)
相關推薦
tarjan演算法模板及其程式碼解釋
首先解釋一下三個概念 強連通(strongly connected): 在一個有向圖G裡,設兩個點 a b 發現,由a有一條路可以走到b,由b又有一條路可以走到a,我們就叫這兩個頂點(a,b)強連通。 強連通圖: 如果 在一個有向圖G中,每兩個點都強連通,我們就叫這個圖,強連通圖。 強連
LCA(最近公共祖先)Tarjan演算法模板
#include <iostream> #include <cstdio> #include <cstring> #include <vector> using namespace std; /** 1.dfs 2.
Tarjan 演算法&模板
Tarjan 演算法 一.演算法簡介 Tarjan 演算法一種由Robert Tarjan提出的求解有向圖強連通分量的演算法,它能做到線性時間的複雜度。 我們定義: 如果兩個頂點可以相互通達,則稱兩個頂點強連通(strongly connected)。如果有向圖G的每兩個頂點都強連通,稱G是一個強
強連通分量-tarjan演算法模板詳解
分析中結合圖形模擬演算法過程,我也是看了這位大牛的文章之後入門tarjan演算法,但是大牛的程式碼中沒有註釋,自己比較笨,看大牛的程式碼也用了很長時間理解,這裡給出大牛的程式碼模板結合自己的詳細解釋,希望以後自己來看一目瞭然,也希望能幫助剛接觸tarjan演算法的人更快理
hdu 2586 How far away?(LCA模板題+離線tarjan演算法)
How far away ? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 25408 &nbs
【演算法模板】Tarjan求強連通分量
#include<iostream> #include<cstring> #include<stack> #include<vector> using namespace std; const int MAXN=1000+1
【模板】LCA Tarjan演算法 (模板題:洛谷P3379)
題目描述 如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。 輸入輸出格式 輸入格式: 第一行包含三個正整數N、M、S,分別表示樹的結點個數、詢問的個數和樹根結點的序號。 接下來N-1行每行包含兩個正整數x、y,表示x結點和y結點之間有一條直接連線的邊
tarjan LCA模板
efi int namespace urn span void scanf 模板 ++ 1 #include<cstdio> 2 #include<iostream> 3 #define MN 300000 4 using namespac
tarjan相關模板
scanf tdi main puts com 連通塊 math spl 一個 感性理解: o(* ̄︶ ̄*)o ^_^ \(^o^)/~ 1. 當根節點有大於兩個兒子時,割掉它,剩下的點必然不聯通(有兩個強連通分量),則他為割點。 那麽對於非根節點,在無向圖G中,剛且
朱劉演算法模板(最小樹形圖)
前向星儲存結構 題為UVA-11183 Teen Girl Squad #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<
【Ex_BSGS&BSGS演算法模板】poj2417 poj3243
題意:給定a,b,p,求最小的非負整數x,滿足 ax ≡ b(mod p) Ex_BSGS,p是不是素數都可以 //#include <bits/stdc++.h> ///複雜度為O(sqrt(n)) #include &l
MATLAB模擬退火演算法模板
為了參加國賽,這幾天學了模擬退火演算法,整理下當做模板方便國賽的時候用。 模擬退火用於處理最優化問題,可以求出當目標函式取得最小值時的決策變數的值。 在編寫程式時需要根據具體問題設計演算法,演算法描述為: (1)解空間(初始解) (2)目標函式 (3)新解的產生 &nbs
TARJAN演算法與其運用
一.割點與割邊 題目連結 http://hihocoder.com/problemset/problem/1183 割點: x不是根:只要有low[v[x]]>=low[x] 說明v[x]不通過x沒法回到x來時的地方,所以x為割點 x是根:x有兩個及以上的直接兒子(注意
圖論初步-Tarjan演算法及其應用
暑假刷了一堆Tarjan題到頭來還是忘得差不多。 這篇部落格權當複習吧。 一些定義 無向圖 割頂與橋 (劃重點) 圖G是連通圖,刪除一個點表示刪除此點以及所有與其相連的邊。 若刪除某點u後G不再連通,那麼u是G的一個割頂(割點)。 若刪除某邊e後G不再連通,那麼e是G的一個橋。 雙連通 一個圖為雙
演算法模板(三)最短路問題
Dijkstra #include<bits/stdc++.h> #define maxn 1000 #define maxm 1000 #define X first #define Y second using namespace std; typedef pair<int,int&g
演算法模板(五)樹基礎演算法
最小生成樹 #include<bits/stdc++.h> #define maxn 5000 #define maxm 10000 using namespace std; inline char get(){ static char buf[30],*p1=buf,*p2=buf;
演算法模板(一) 01揹包,多重揹包,完全揹包
01揹包 #include<bits/stdc++.h> using namespace std; int dp[300][3000]; int w[3000],v[3000]; int N,V; int main(){ cin>>N>>V; for(re
演算法模板(二)子序列問題
最長公共子序列 #include<bits/stdc++.h> using namespace std; int dp[200][200]; int lena,lenb,n; int a[200],b[200]; int main(){ cin>>n; for(reg
演算法模板(六)基礎數論
gcd與lcm #include<bits/stdc++.h> using namespace std; int gcd(int x,int y){ if(b==0)return a; return gcd(b,a%b); } int lcm(int x,int y){
演算法模板(七) 線段樹
線段樹單點操作 #include<bits/stdc++.h> using namespace std; int a[maxn],sumv[maxn*4]; void pushup(int id){ sumv[id]=sumv[id<<1]+sumv[id<<1