1. 程式人生 > >Tarjan 演算法&模板

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