强连通分量(strongly connected components)

强连通分量(strongly connected components)

                                                                                                                             徐不可说        2018/8/4                                                        

定义(有向图): 

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

例如:

强连通分量(strongly connected components)_第1张图片

在此图中{1,2,3,4} {5} {6}为强连通分量。

 

 

Korasaju算法

首先要先理解一下转置图的定义:将有向图G中的每一条边反向形成的图称为G的转置G T 。(注意到原图和G T 的强连通分支是一样的)

 

算法思想:

1.深度优先遍历G,算出每个结点u的结束时间f[u],起点如何选择无所谓。

2.深度优先遍历G的转置图G T ,选择遍历的起点时,按照结点的结束时间从大到小进行。遍历的过程中,一边遍历,一边给结点做分类标记,每找到一个新的起点,分类标记值就加1。

3. 第2步中产生的标记值相同的结点构成深度优先森林中的一棵树,也即一个强连通分量。

 

下图为Korasaju算法寻找最强连通分量的一个例子:

强连通分量(strongly connected components)_第2张图片

图(a)是正图遍历 执行dfs

图(b)是逆图遍历 执行dfs、删除顶点

 

Korasaju算法比较关键的部分是同时应用了原图G和反图GT。 先用对原图G进行深搜形成森林(树), 然后任选一棵树对其进行深搜(注意这次深搜节点A能往子节点B走的要求是EAB存在于反图GT),能遍历到的顶点就是一个强连通分量。余下部分和原来的森林一起组成一个新的森林,继续步骤2直到 没有顶点为止。

 

以下为c++实现过程:

void dfsOne(int x)
{
	vst[x]=1;
for(int i=1;i<=n;i++)
	if(!vst[i]&&map[x][i])dfsOne(i);
d[++t]=x;
}
void dfsTwo(int x)
{
	vst[x]=t;
	for(int i=1;i<=n;i++)
		if(!vst[i]&&map[i][x])dfsTwo(i);	
}
void kosaraju()
{
	int i,t=0;
	for(int i=1;i<=n;i++)
		if(!vst[i])dfsOne(i);
	memset(vst,0,sizeof(vst));
	t=0;
	for(int i=n;i>=1;i--)
		if(!vst[d[i]]){t++;dfsTwo(d[i]);}
}

 

 

Tarjan算法

Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。总的来说, Tarjan算法基于一个观察,即:同处于一个SCC中的结点必然构成DFS树的一棵子树。 我们要找SCC,就得找到它在DFS树上的根。其实,我们只要确定每个强连通分量的子树的根,然后根据这些根从树的最低层开始,一个一个的拿出强连通分量即可。那么剩下的问题就只剩下如何确定强连通分量的根和如何从最低层开始拿出强连通分量了。

 

算法思想:  

dfn[u]表示dfs时达到顶点u的次序号(时间戳),low[u]表示以u为根节点的dfs树中次序号最小的顶点的次序号,所以当dfn[u]=low[u]时,以u为根的搜索子树上所有节点是一个强连通分量。 先将顶点u入栈,dfn[u]=low[u]=++idx,扫描u能到达的顶点v,如果v没有被访问过,则dfs(v),low[u]=min(low[u],low[v]),如果v在栈里,low[u]=min(low[u],dfn[v]),扫描完v以后,如果dfn[u]=low[u],则将u及其以上顶点出栈。

 

以下为c++实现过程:

void tarjan(int u){
	dfn[u]=low[u]=++num;
	st[++top]=u;
	for(int i=fpr[u];i;i=nex[i])
	{
		int v=to[i];
		if(!dfn[v])
		{
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
else if (!co[v])
	low[u]=min(low[u],low[v]);
	}
	if(low[u]==dfn[u])
	{
		co[u]=++col;
		while(st[top]!=u)
		{
			co[st[top]]=col;
			--top;
		}
		--top;
	}
}

 

你可能感兴趣的:(强连通分量(strongly connected components))