强连通分量(Tarjan算法)

强连通分量

       有向图强连通分量:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量。

强连通分量(Tarjan算法)_第1张图片

强连通分量(Tarjan算法)_第2张图片

 

        Tarjan 算法是基于对图优先搜素的算法 , 每个强连通分量为搜索树中的一棵子树 .搜索时,把当前搜索树中未处理的节点加入一个堆栈 ,回溯时可以判断栈顶到栈中节点是否为一个强连通分量 . 

         定义 dfn[u] 为节点u搜索的次序编号(时间戳) ,low[u]  为u 或u的子树能够追溯到的最早的栈中节点的次序号 . 

         当dfn[u] = low[u]  时 , 以 u 为根的搜索子树上所有节点时一个强连通分量 , 伪代码 : 

 

强连通分量(Tarjan算法)_第3张图片

算法流程 :

强连通分量(Tarjan算法)_第4张图片

强连通分量(Tarjan算法)_第5张图片

强连通分量(Tarjan算法)_第6张图片

 模板 :  https://www.luogu.org/problemnew/show/P2863

邻接表存图

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
const int MAX = 10010 ;
vector  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 ; i1){
			ans++ ;
		}
	}
	cout<

链式前向星 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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 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<1){
			ans++ ;
		}
	}
	cout<

 

 

 

 

你可能感兴趣的:(算法)