tarjan求强连通分量模板

来源:互联网 发布:支付宝登陆淘宝 编辑:程序博客网 时间:2024/05/07 22:57

在有向图中,如果两个顶点间至少存在一条路径,称两个顶点强连通。

如果有向图G的每两个顶点都强连通,称G是一个强连通图。

非强连通图有向图的极大强连通子图,称为强连通分量。


而用tarjan算法可以起求出各个强连通分量,然后再把强连通分量缩成一个点,非强连通图就被转换成一个

DAG,去多问题都是在此基础上求解。

以下是模板:

#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <stack>using namespace std;#define maxn 10010vector <int> G[maxn];int pre[maxn], lowlink[maxn], sccno[maxn], dfs_clock, scc_cnt;//scc_cnt为SCC的计数器,sccno[i]为i所在SCC的编号stack <int> S;int out0[maxn];void dfs(int u){    pre[u]=lowlink[u]=++dfs_clock;    S.push(u);    for(int i = 0; i < G[u].size(); i++)    {        int v=G[u][i];        if(!pre[v]) //如果没有访问则访问        {            dfs(v);            lowlink[u]=min(lowlink[u],lowlink[v]);        }else if(!sccno[v]) //如果访问了且在栈中            lowlink[u]=min(lowlink[u],pre[v]);    }    if(lowlink[u]==pre[u])    {        scc_cnt++;        while(1)        {            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(pre,0,sizeof(pre));    for(int i = 1; i <= n; i++)if(!pre[i])dfs(i);//节点编号从1开始}int main(){    int n,m;    while(~scanf("%d%d",&n,&m))    {        for(int i = 0; i <= n; i++)G[i].clear();        for(int i = 0; i < m; i++)        {            int a,b;            scanf("%d%d",&a,&b);            G[a].push_back(b);        }        find_scc(n);        if(scc_cnt==1)        {            printf("%d\n",n);            continue;        }        memset(out0,0,sizeof(out0));        for(int u = 1; u <= n; u++)        for(int i = 0; i < G[u].size(); i++)        {            int v = G[u][i];            if(sccno[u]!=sccno[v])                out0[sccno[u]]++;        }        int a=0,id;        for(int i = 1; i <= scc_cnt; i++)            if(out0[i]==0){a++;id=i;}        if(a==1)        {            int ans = 0;            for(int i = 1; i <= n; i++)                if(sccno[i]==id)ans++;            printf("%d\n",ans);        }        else        {            printf("0\n");        }    }    return 0;}


原创粉丝点击