tarjan模板完整版

https://www.luogu.org/problem/P2863

#include<cstdio>
#include<vector>
using namespace std;
int dfn[10005],low[10005],stack[10005],scc[10005],num[10005],vis[10005];
int clock,scc_cnt,top;
vector<int>e[10005];
inline void dfs_scc(int x)
{
    dfn[x]=low[x]=++clock;//访问次序标记;x能到的祖先中节点编号最小的 
    stack[++top]=x;//把走过的节点入栈 
    vis[x]=1;
    for(int i=0;i<e[x].size();i++)
    {
        int now=e[x][i];
        if(!dfn[now])//如果没有被访问过 
        {
            dfs_scc(now);//进它 
            low[x]=min(low[x],low[now]);//既然now是x的子节点,那么他们一定有公告的祖先,取个小的 
        } 
        else
        if(vis[now])//如果他还没有被其他强连通分量使用 
        low[x]=min(low[x],dfn[now]);//那么再小一点 
    }
    if(low[x]==dfn[x])
    {
        scc_cnt++;
        while(stack[top]!=x)
		{
		//x节点在栈中夹着的节点就是强连通分量的节点 
       		scc[stack[top--]]=scc_cnt;
       		vis[stack[top+1]]=0;
       		num[scc_cnt]++;
		}//哪一个点在当前编号为scc_cnt的强连通分量里 
        top--;
        vis[x]=0;
        num[scc_cnt]++;
        scc[x]=scc_cnt;//一个强连通分量 
    } 
} 
int main()
{
	int n,m,a,b;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&a,&b);
		e[a].push_back(b);
		//e[b].push_back(a);
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		if(dfn[i]==0)
		{
			dfs_scc(i);
		}
	}
	for(int i=1;i<=scc_cnt;i++)
	{
		if(num[i]>1)
		{
			ans++;
		}
	}
	printf("%d\n",ans);
	return 0;
}
posted @ 2019-08-11 10:03  ShineEternal  阅读(186)  评论(0编辑  收藏  举报