强连通图(tarjan)模板和详解

来一道裸代码。
输入:
一个图有向图。
输出:
它每个强连通分量。

这个图就是刚才讲的那个图。一模一样。

input:

6 8

1 3

1 2

2 4

3 4

3 5

4 6

4 1

5 6

output:

6

5

3 4 2 1

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<algorithm>
#include<map>
#define maxn 200005
using namespace std;
struct node
{
    int v,next;  //v表示指向的点  next表示
}mp[1005];
int DFN[1005],LOW[1005];   //DFN[]作为这个点搜索的次序编号(时间戳)
                           //LOW[]作为每个点在这颗树中的,最小的子树的根,每次保证最小,like它的父亲结点的时间戳这种感觉
int stack[1005],heads[1005],visit[1005],cnt,tot,index;
 // 栈          访问顺序    是否访问        
void add(int x,int y)
{
   mp[++cnt].next=heads[x];
   mp[cnt].v=y;
   heads[x]=cnt;
   return ;
}
void tarjan(int x)
{
    DFN[x]=LOW[x]=++tot;  //初始化x
    stack[++index]=x;     //进栈
    visit[x]=1;           //表示x已经入栈
    for(int i=heads[x];i!=-1;i=mp[i].next){
        if(!DFN[mp[i].v])  //如果没有被访问
    {
       tarjan(mp[i].v);  //往下延伸就是递归
       LOW[x]=min(LOW[x],LOW[mp[i].v]);  //递归出来,比较谁是谁的儿子/父亲,就是树的对应关系,涉及到强连通分量子树最小根的事情
    }
    else if(visit[mp[i].v]) //如果访问过,并还在栈里
    {
        LOW[x]=min(LOW[x],DFN[mp[i].v]);  //比较谁是谁的儿子/父亲。就是链接对应关系
    }
    }
    if(LOW[x]==DFN[x]){ //发现整个连通分量子树里的最小根
        while(1)
    {
        cout<<stack[index]<<" ";
        visit[stack[index]]=0;
        index--;
        if(x==stack[index+1]) break; //出栈,并且输出
    }
    cout<<endl;
  }
}
int main()
{
    memset(heads,-1,sizeof(heads));
    int n,m;
    cin>>n>>m;
    int x,y;
    for(int i=1;i<=m;i++)
    {
        cin>>x>>y;
        add(x,y);
    }
    for(int i=1;i<=n;i++)
    {
        if(!DFN[i])tarjan(i); //当这个点没有访问过,就从这个点开始,防止图没有走完
    }
    return 0;
}

还有各大理解网站:   (杂着看,就可以看懂)

http://blog.miskcoo.com/2016/07/tarjan-algorithm-strongly-connected-components

https://blog.csdn.net/mengxiang000000/article/details/51672725

https://www.cnblogs.com/yxysuanfa/p/7396057.html

原文地址:https://www.cnblogs.com/huangzzz/p/8922029.html