强连通分量

这次我们来讲讲强连通分量 与 边双连通分量。

首先什么是强连通分量?

强连通分量指的是,在“有向图”中任意两个点能相互达到的联通块。

例如 

                  这为一个强连通分量                                         这不是一个强连通分量


那如何去求出这样的分量呢。这就涉及到了tarjan算法。

Tarjan:
本质上就是DFS
需要在dfs的时候记录2个数组:dfn[],low[]
dfn[x]代表x点dfs到的时间,即时间戳,可知在同一个dfs树的子树中,dfn[x]越小,则其越浅。
low[x]代表在dfs树中,此点以及其后代指出去的边,能返回到的最浅的点的时间戳。

例如这张图

其缩点为
详细的过程例如以下的图



代码如下
#include<stdio.h>
#include<string.h>
#include<iostream>
#define N 105
using namespace std;
int n;
struct edge// 用链式前向星存储
{
	int v,next;
	edge(){}
 	edge(int v,int next)
 	{
  		this->v=v;
  		this->next=next;
 	}
}ed[N*N];
int head[N],lnum;
void addline(int u,int v)//添加新边
{
	ed[lnum]=edge(v,head[u]);
	head[u]=lnum++;
}
int index=0;
int dfn[N],low[N],sta[N];//dfn用来标记dfs序时间戳  low标记该点能达到的最小的时间戳的点
int scc[N];  //scc用来存储点所属强连通分量的标号
int top=0,sccnum=0;
void init()
{
	memset(dfn,0,sizeof(dfn));
	memset(scc,0,sizeof(scc));
	memset(head,-1,sizeof(head));
	sccnum=index=top=lnum=0;
}
void tarjan(int root)
{
	dfn[root]=low[root]=++index;
	sta[top++]=root;
	for(int i=head[root];~i;i=ed[i].next)
	{
		int y=ed[i].v;
		if(!dfn[y])
		{
			tarjan(y);
			low[root]=min(low[root],low[y]);
		}
		else if(!scc[y])
		{
			low[root]=min(low[root],dfn[y]);
		}
 	}
 	if(low[root]==dfn[root])
 	{
  		int x;
  		sccnum++;
  		do
  		{
   			x=sta[--top];
   			scc[x]=sccnum;
		}while(x!=root);
 	}
}

对于强连通分量,经常还需要缩点建图,上述代码中,我们有个scc[]数组,表示x这个点所属的scc的编号。
那么建图的话,只需要遍历原有的边,如果边所对应的两个节点所属的scc编号不同,那么则添边,最后得到一个有向无环图。







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值