Luogu2863:利用Tarjan求有向图的强连通分量

强连通分量这这样的一个子图:

图中的任意两点都可以相互通达,它是有向图

这里的例题题意是这样的,统计所有强连通分量中,至少包含两个点的强连通分量的数量

const int maxn=10005;
const int maxm=50005;
int n,m,cnt,deep,top,sum,ans;
int g[maxn],vis[maxn],dfn[maxn<<1],low[maxn<<1],st[maxn<<1],col[maxn],tot[maxn];
struct Edge{int t,next;}e[maxm];

这里面把强连通分量的点放在st栈里,用vis进行存在性标记

col的意思是下标属于哪一个强连通分量,tot是用来统计每一种强连通分量所包含的顶点数量的

void tarjan(int u)
{
    dfn[u]=++deep;low[u]=deep;
    vis[u]=1;
    st[++top]=u;
    for(int tmp=g[u];tmp;tmp=e[tmp].next)
    {
        int v=e[tmp].t;
        if(!dfn[v]) {tarjan(v);low[u]=min(low[u],low[v]);}
        else if(vis[v]) low[u]=min(low[u],low[v]);
    }
    if(dfn[u]==low[u])
    {
        col[u]=++sum;vis[u]=0;
        while(st[top]!=u)
        {
            col[st[top]]=sum;
            vis[st[top--]]=0;
        }
        top--;
    }
}

这里的Tarjan还是很显然的,与之前的两种大同小异

最后给出完整的实现:

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int maxn=10005;
 5 const int maxm=50005;
 6 int n,m,cnt,deep,top,sum,ans;
 7 int g[maxn],vis[maxn],dfn[maxn<<1],low[maxn<<1],st[maxn<<1],col[maxn],tot[maxn];
 8 struct Edge{int t,next;}e[maxm];
 9 void addedge(int u,int v)
10 {
11     e[++cnt].t=v;
12     e[cnt].next=g[u];g[u]=cnt;
13 }
14 void tarjan(int u)
15 {
16     dfn[u]=++deep;low[u]=deep;
17     vis[u]=1;
18     st[++top]=u;
19     for(int tmp=g[u];tmp;tmp=e[tmp].next)
20     {
21         int v=e[tmp].t;
22         if(!dfn[v]) {tarjan(v);low[u]=min(low[u],low[v]);}
23         else if(vis[v]) low[u]=min(low[u],low[v]);
24     }
25     if(dfn[u]==low[u])
26     {
27         col[u]=++sum;vis[u]=0;
28         while(st[top]!=u)
29         {
30             col[st[top]]=sum;
31             vis[st[top--]]=0;
32         }
33         top--;
34     }
35 }
36 int main()
37 {
38     scanf("%d%d",&n,&m);
39     int u,v;
40     for(int i=1;i<=m;i++)
41     {
42         scanf("%d%d",&u,&v);
43         addedge(u,v);
44     }
45     for(int i=1;i<=n;i++)
46         if(!dfn[i]) tarjan(i);
47     for(int i=1;i<=n;i++) tot[col[i]]++;
48     for(int i=1;i<=sum;i++)
49         if(tot[i]>1) ans++;
50     printf("%d\n",ans);
51     return 0;
52 }

猜你喜欢

转载自www.cnblogs.com/aininot260/p/9428798.html