浅谈Tarjan算法

Tarjan算法:

Tarjan算法是一种用于查找已知图中的强连通分量的方法(介绍似乎越来越草率了

时间复杂度:O(n+m)//n为点数,m为边数

算法思路

1,首先对每个节点设置两个参数存储:dfn[i]表示第i个点被搜索到的次序编号(每个点的dfn值都不同,low[i]表示每个点在这棵树中的最小子树根(人话就是找爹;

2,对每个新节点,初始化零dfn[i]=low[i];

3,用栈作为容器存储新出现的节点,若这个点有出度,就依次遍历每个子节点,每次都更新最小值保证子树根最小;

4,若找到dfn[i]=low[i],则i为本强连通分量中的根节点,将i及比i后进栈的元素出栈,即为一个强连通分量;

5,应在循环中调用tarjan函数,使每个没被访问过的点都被访问到。

似乎没找到板子题那就自己创造板子吧。

似乎很简单不太用注释的样子(记得要单独开一个数组记录哪些点已经在别的强连通分量中了

#include
#define ri register int
using namespace std;
const int N=1e4;
int n,m;
int head[N],cnt;
bool vis[N],jilu[N];
int dfn[N],low[N],tot;
struct qwq{
    int to,nxt;
}e[N];
stack s;
void add(int u,int v){
    e[++cnt].to=v;
    e[cnt].nxt=head[u];
    head[u]=cnt;
}
void tarjan(int x){
    dfn[x]=low[x]=++tot;
    s.push(x);
    vis[x]=1;
    for(ri i=head[x];i;i=e[i].nxt){
        int v=e[i].to;
        if(!dfn[v]){
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }
        else if(vis[v]) low[x]=min(dfn[v],low[x]);
    }
    if(low[x]==dfn[x]){
        for(;;){
            int u=s.top();
            s.pop();
            vis[u]=0,jilu[u]=1;
            printf("%d ",u);
            if(u==x) break;
            
        }
        putchar('\n');
    }
}
int main(){
    scanf("%d%d",&n,&m);
    int x,y;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    for(int i=1;i<=n;i++) if(!jilu[i]) tarjan(i);
    return 0;
}

你可能感兴趣的:(算法,算法,图论)