強連通分量(Tarjan演算法)
強連通分量
有向圖強連通分量:在有向圖G中,如果兩個頂點vi,vj間(vi>vj)有一條從vi到vj的有向路徑,同時還有一條從vj到vi的有向路徑,則稱兩個頂點強連通。如果有向圖G的每兩個頂點都強連通,稱G是一個強連通圖。有向圖的極大強連通子圖,稱為強連通分量。
Tarjan 演算法是基於對圖優先搜素的演算法 , 每個強連通分量為搜尋樹中的一棵子樹 .搜尋時,把當前搜尋樹中未處理的節點加入一個堆疊 ,回溯時可以判斷棧頂到棧中節點是否為一個強連通分量 .
定義 dfn[u] 為節點u搜尋的次序編號(時間戳) ,low[u] 為u 或u的子樹能夠追溯到的最早的棧中節點的次序號 .
當dfn[u] = low[u] 時 , 以 u 為根的搜尋子樹上所有節點時一個強連通分量 , 虛擬碼 :
演算法流程 :
模板 : https://www.luogu.org/problemnew/show/P2863
鄰接表存圖
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
using namespace std;
const int MAX = 10010 ;
vector <int> g[MAX] ;
int color[MAX] ;
int dfn[MAX] ; // 表示dfs時第幾個被搜到的
int low[MAX] ; // 表示這個點以及其子孫節點連的所有點中dfn最小的值
int stack[MAX] ; //當前所有可能能構成強連通分量的點
int vis[MAX] ; // 標記
int cnt[MAX] ;
int deep ,top , n , m, sum , ans ;
void tarjan(int u ){
dfn[u] = ++deep ;
low[u] = deep ;
vis[u] = 1 ;// 記錄是否在棧中
stack[++top] = u ;
for(int i = 0 ; i<int(g[u].size()) ;i++){
int v = g[u][i] ; // 鄰接的子孫節點 ;
if(!dfn[v]){
tarjan(v) ;
low[u] = min(low[u],low[v]) ;
}
else{
if(vis[v]){
low[u] = min(low[u],dfn[v]) ;
}
}
}
if(dfn[u]==low[u]){
color[u]= ++sum ;
vis[u] = 0 ;
while(stack[top]!=u){
color[stack[top]] = sum ;
vis[stack[top--]] = 0 ;
}
top-- ;
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1 ; i <= m ;i++){
int u , v ;
scanf("%d%d",&u,&v);
g[u].push_back(v) ;
}
for(int i = 1 ; i<=n ; i++ ){
if(!dfn[i]){
tarjan(i) ;
}
}
for(int i = 1 ; i<=n ; i++ ){
cnt[color[i]]++ ;
}
for(int i = 1 ; i<=sum ; i++ ){
if(cnt[i]>1){
ans++ ;
}
}
cout<<ans ;
return 0;
}
鏈式前向星
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <stack>
using namespace std;
const int MAX = 100100 ;
int n , m , idx ;
int cnt ,Bcnt ;
int head[MAX] ;
int vis[MAX] ;
int dfn[MAX] ,low[MAX] ;
int Belong[MAX] ;
stack<int> s ;
struct edge{
int v ;
int next ;
}e[MAX] ;
void add(int u , int v){
e[++cnt].v = v ;
e[cnt].next = head[u] ;
head[u] = cnt++ ;
}
void tarjan(int u ){
int v;
dfn[u] = low[u] = ++idx ; // 每次dfs , u的次序號加一
s.push(u) ; // 將u 進棧
vis[u] = 1 ; // 標記u已經在棧內
for(int i = head[u] ;i!=-1 ; i= e[i].next ){
v = e[i].v;
if(!dfn[v]){ // 如果還沒處理過
tarjan(v) ;
low[u] = min(low[u],low[v]) ;//如果v在棧內,u點能到達的最小次序號是它自己能到達點的
// 最小次序號和v的次序號中較小的
}
else{
if(vis[v]){
low[u] = min(low[u],dfn[v]) ;
}
}
}
if(dfn[u] == low[u]){
Bcnt++ ;
do{
v = s.top() ;
s.pop() ;
vis[v] = 0 ;
Belong[v] = Bcnt ;
}while(u!=v) ;
}
}
int main(){
cin >> n >> m ;
memset(head,-1,sizeof(head)) ;
for(int i = 1 ; i<=m ; i++ ){
int u , v;
cin >>u >>v ;
add(u,v) ;
}
for(int i = 1 ; i<=n ; i++){
if(!dfn[i]){
tarjan(i) ;
}
}
// cout<<endl;
// for(int i = 1 ; i<=6 ; i++){
// cout<<dfn[i] <<" "<<low[i] <<endl ;
// }
// cout<<" 有"<<Bcnt<<" 個強連通分量 "<<endl ;
// for(int i = 1 ; i<=Bcnt; i++ ){
// cout<<i<<" : " ;
// for(int j = 1 ; j<=n ; j++){
// if(Belong[j]==i){
// cout<<j <<" " ;
// }
// }
// cout<<endl;
// }
int ans = 0 ;
for(int i = 1 ; i<=Bcnt ; i++ ){
int num = 0 ;
for(int j = 1; j<=n ; j++ ){
if(Belong[j]==i){
num++ ;
}
}
if(num>1){
ans++ ;
}
}
cout<<ans;
return 0;
}
相關文章
- 圖之強連通、強連通圖、強連通分量 Tarjan演算法演算法
- Tarjan演算法(強連通分量分解)演算法
- 圖論——強連通分量(Tarjan演算法)圖論演算法
- Tarjan演算法求強連通分量總結演算法
- 強連通分量-tarjan演算法模板詳解演算法
- kosaraju 和 tarjan演算法詳解(強連通分量)演算法
- Tarjan演算法三大應用之強連通分量演算法
- 強連通分量及縮點tarjan演算法解析演算法
- 【模板】tarjan 強連通分量縮點
- Tarjan 求有向圖的強連通分量
- 尋找圖的強連通分量:tarjan演算法簡單理解演算法
- POJ 2186 Popular Cows(強連通分量縮點,Tarjan演算法)演算法
- 20行程式碼實現,使用Tarjan演算法求解強連通分量行程演算法
- 圖論複習之強連通分量以及縮點—Tarjan演算法圖論演算法
- 強連通演算法--Tarjan個人理解+詳解演算法
- 強連通分量與縮點(Tarjan演算法)(洛谷P3387)演算法
- 連通圖與Tarjan演算法演算法
- 強連通分量
- HDU 2767 Proving Equivalences Tarjan 強連通縮點UI
- 強連通------tarjan演算法詳解及與縮點聯合運用演算法
- 演算法學習之路|強連通分量+縮點演算法
- 【筆記】tarjian演算法 求強連通分量筆記演算法
- 【演算法學習】tarjan 強連通、點雙、邊雙及其縮點 重磅來襲!!!!演算法
- 連通圖演算法詳解之① :Tarjan 和 Kosaraju 演算法演算法
- 強連通分量及縮點 演算法解析及例題演算法
- 強連通圖的演算法演算法
- Trajan演算法(強連通+縮點)演算法
- HDU2767Proving Equivalences[強連通分量 縮點]UI
- 求有向圖的強連通分量(c語言版)C語言
- Tarjan演算法_縮點演算法
- 抓間諜(強連通)
- 邊分治維護強連通分量(CF1989F,P5163)
- tarjan—演算法的神(一)演算法
- Tarjan(連通性相關) 筆記筆記
- 有向圖的連通性(判強連通)
- tarjan演算法求scc & 縮點演算法
- Tarjan 演算法學習筆記演算法筆記
- 【Tarjan SCC 加邊使得所有圖聯通 至少選取多少個點能圖聯通 】Network of Schools加強版.md