tarjan 强连通 模板

2SAT中的重要知识 以前学过忘记存了。现在存一发免得再忘了

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <cmath>
#include <map>
#include <string>
#include <stack>
#include <queue>

using namespace std;
const int MAXN=1e5+10;
struct node
{
    int v;
    int nxt;
};
node edge[MAXN];//边数
int head[MAXN];
int n,m;
int Stop,Bcnt,Dindex;//栈头,强通块数,时间戳
int DFN[MAXN],LOW[MAXN];//首时间戳,最近回溯点(根)
int Stap[MAXN];//答案栈
int instack[MAXN];//是否在栈中
int Belong[MAXN];//这个点属于第几个强连通块(点)
int cnt=0;
void add_edge(int u,int v)
{
    edge[cnt].v=v;
    edge[cnt].nxt=head[u];
    head[u]=cnt;
    cnt++;
}
void tarjan(int i)
{
    int j;
    DFN[i]=LOW[i]=++Dindex;
    instack[i]=1;
    Stap[++Stop]=i;
    for (int e=head[i]; e!=-1; e=edge[e].nxt)
    {
        j=edge[e].v;
        if (!DFN[j])//儿子没遍历
        {
            tarjan(j);//遍历
            if (LOW[j]<LOW[i])//如果儿子已经形成环
                LOW[i]=LOW[j];//父亲也要在回溯的时候进入环
        }
        else if (instack[j]&&DFN[j]<LOW[i])//邻接的在栈里,所以是大大
            LOW[i]=DFN[j];//把这个点归到大大那
    }
    if (DFN[i]==LOW[i])//这个点的根是自己
    {
        Bcnt++;//多了一个强连通分量
        do
        {
            j=Stap[Stop--];//退栈
            instack[j]=0;//标记
            Belong[j]=Bcnt;//标记
        }
        while (j!=i);
    }
}
void solve()
{
    int i;
    Stop=Bcnt=Dindex=0;//栈头,强通块数,时间戳
    memset(DFN,0,sizeof(DFN));
    for (int i=1; i<=n; i++)
        if (!DFN[i])
            tarjan(i);
}
int main()
{
    while (scanf ("%d%d",&n,&m)!=EOF)
    {
        memset(head,-1,sizeof(head));
        while (m--)
        {
            int t1,t2;
            scanf ("%d%d",&t1,&t2);
            add_edge(t1,t2);
        }
        solve();
    }
    return 0;
}

 

posted on 2016-07-27 15:20  very_czy  阅读(143)  评论(0编辑  收藏  举报

导航