现在的位置: 首页 > 综合 > 正文

强连通分量及缩点tarjan算法解析

2013年11月10日 ⁄ 综合 ⁄ 共 1568字 ⁄ 字号 评论关闭

强连通分量:

简言之 就是找环(每条边只走一次,两两可达)

孤立的一个点也是一个连通分量

 

使用tarjan算法 在嵌套的多个环中优先得到最大环( 最小环就是每个孤立点)

 

定义:

int Time, DFN[N], Low[N];

DFN[i]表示 遍历到 i 点时是第几次dfs

Low[u] 表示 以u点为父节点的 子树 能连接到 [栈中] 最上端的点

 

int Stack[N], top; //栈用来记录所有走过的点(因为是dfs过程,首先从根节点走到叶子节点再进行处理 所以栈中存的是
唯一一条路径 (无分叉)

 

tarjan的过程就是dfs过程

是对树dfs (对于一些会连会 走过的边 (成为反向边|横向边))

显然图中只有树边和这样的反向边

对于树,加一条边就会成环,显然 对于反向边的2个端点 [u,v]  (这样得到一个环是 [u, u到v的路径, v]  ,之前提到因为dfs所以栈中存的是唯一路径,退栈就能得到u->v的路径

从dfs算法可以得到每个点至多入栈一次,因此每个点都只存在于一个强连通分量中

图中 红线和蓝线(蓝线为左边中间那条)为反向边

注意Low【】数组的定义:low[u]  表示u的子树中 所有反向边能连接到 最高的 u的父节点 (所以用时间戳数组DFN[]来判断反向边连接到的节点是u的子节点还是u的父节点(即数值小的就是父节点)

当现在dfs 到 u点,子节点 v 的反向边,能走到最高处是 f 点,所以 Low[ v ] = DFN[ f ];

根据定义 Low[u] = Low[ v ] = DFN[ f ];

if( DFN[ u ] >= Low[ u ] ) 则u 是割点

图中 DFN[ v ] > Low[ v ] , DFN[ u ] > Low[ u ] ,而这个环(v u f ) 以v为起点 ,则 f 为终点 因为点f : DFN[ f ] == Low[ f ]

所以当 回溯到 f点时, if( DFN[f] == Low[ f ] ) 则路径上的所有点都是割点(即栈中所有点)

这样就能得到 环【v u f】

 

 

 

#define N 22000
//N为点数
#define M 55000
//M为边数

struct Edge{
	int from, to, nex;
	bool sign;//表示边是否使用过(处理重边的情况)
}edge[M];
int head[N], edgenum;
void addedge(int u, int v){
	Edge E={u, v, head[u], false};
	edge[ edgenum ] = E;
	head[u] = edgenum++;
}

int DFN[N], Low[N], Stack[N], top, Time;
int taj;//连通分支标号
int Belong[N];//Belong[i] 表示i点属于的连通分支
bool Instack[N];

void tarjan(int u ,int fa){  
	DFN[u] = Low[u] = ++ Time ;  
	Stack[top ++ ] = u ;  
	Instack[u] = 1 ;  

	for (int i = head[u] ; i!=-1 ; i = edge[i].nex ){  
		int v = edge[i].to ;  
		if(DFN[v] == -1)
		{  
			tarjan(v , u) ;  
			Low[u] = Min(Low[u] ,Low[v]) ;
			if(DFN[u] < Low[v])
			{
				edge[i].sign = 1;//为割桥
			}
		}  
		else if(Instack[v]){  
			Low[u] = Min(Low[u] ,DFN[v]) ;  
		}
	}  
	if(Low[u] == DFN[u]){  
		int now ;
		taj ++ ; 
		do{
			now = Stack[-- top] ;  
			Instack[now] = 0 ; 
			Belong [now] = taj ;
		}while(now != u) ;
	}
}

void tarjan_init(){
	memset(head, -1, sizeof(head)); edgenum = 0;
	memset(DFN, -1, sizeof(DFN));
	memset(Instack, 0, sizeof(Instack));
	top = Time = taj = 0;
}

抱歉!评论已关闭.