Tarjan算法

来源:互联网 发布:淘宝怎么开店好赚钱呢 编辑:程序博客网 时间:2024/06/11 00:08
Tarjan算法用于求有向图的强连通分量(强连通分支)。
(1)”强连通分量“的概念:
有向图强连通分量在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量(strongly connected components)。 简称scc
(2)Tarjan算法原理
设u为scc的根(第一个被发现的结点)那么不存在一条路径从u到达它的祖先,同时也不存在这样的路径从u的子结点v到达u的祖先。借助这条原理我们定义:
lowlink(u)为u及其后代所能追溯到的最早(最先被发现)祖先点v的dfn(v)值。
dfn[v]记录v被访问的时间(时间戳)也可以理解为再访问该结点前已经访问的结点数;
scc_cnt为scc计数器;
sccno[i]为i所在的scc编号;
核心代码;

vector<int>G[maxn];
int dfn[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt;
stack<int>S;

void dfs(int u)
{
dfn[u]=lowlink[u]=++dfs_clock;
S.push(u);
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(!dfn[v])
{
dfs(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
}
else if(!sccno[v]) lowlink[u]=min(lowlink[u],dfn[v]);
}
if(lowlink[u]==dfn[u])
{
scc_cnt++;
for(;;)
{
int x=S.top();S.pop();
sccno[x]=scc_cnt;
if(x==u)break;
}
}
}
void find_scc(int n)
{
dfs_clock=scc_cnt=0;
memset(sccno,0,sizeof(sccno));
memset(dfn,0,sizeof(dfn));
for(int i=1;i<=n;i++)
if(!dfn[i])dfs(i);
}


0 0