1 #include<bits/stdc++.h>
2 using namespace std;
3 int n,m;
4 struct edge{
5 int next,to;
6 }e[1000];
7 int tot;
8 int first[10009];
9 int dfn[10009];
10 int low[10009];
11 int ans;
12 int sum;
13 int sta[10009];
14 bool insta[10009];
15 int top;//表示栈顶位置
16 int id[100009];//标记是哪一组的
17 void add_edge(int a,int b)
18 {
19 tot++;
20 e[tot].next=first[a];
21 first[a]=tot;
22 e[tot].to=b;
23 }
24 void dfs(int now)
25 {
26 sum++;
27 low[now]=sum,dfn[now]=sum;
28 top++;
29 sta[top]=now,insta[now]=true;
30 for(int i=first[now];i;i=e[i].next)
31 {
32 if(dfn[e[i].to]==0)
33 {
34 dfs(e[i].to);
35 if(low[e[i].to]<low[now])
36 {
37 low[now]=low[e[i].to];
38 }
39 }
40 else
41 {
42 if(insta[e[i].to]==true&&dfn[e[i].to]<low[now])
43 {
44 low[now]=dfn[e[i].to];
45 }
46 }
47 }
48 if(low[now]==dfn[now])
49 {
50 ans++;
51 int p=sta[top];
52 while(p>now)
53 {
54 id[p]=ans;
55 insta[p]=false;
56 top--;
57 p=sta[top];
58 }
59 top--;
60 id[now]=ans;
61 insta[now]=false;
62 }
63 }
64 int main()
65 {
66 cin>>n>>m;
67 for(int i=1;i<=m;i++)
68 {
69 int a,b;
70 cin>>a>>b;
71 add_edge(a,b);
72 }
73 for(int i=1;i<=n;i++)
74 {
75 if(dfn[i]==0)dfs(i);
76 }
77 cout<<ans<<endl;
78 for(int i=1;i<=n;i++)
79 {
80 printf("%d属于第%d个强连通分量\n",i,id[i]);
81 }
82 }
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<iostream>
5 #include<algorithm>
6 using namespace std;
7
8 const int maxn = 10001;
9 const int maxm = 10001;
10 int first[maxn],id[maxn]; //id[i]表示:i点所属强连通分量的编号
11 int next[maxm],en[maxm];
12 int dfn[maxn],low[maxn],sta[maxn];
13 bool insta[maxn];
14 int tot=0,sign=0,top=0,n,m,a,b,sum=0,i;
15
16 void Add(int x, int y)
17 {
18 tot++;
19 next[tot]=first[x];
20 first[x]=tot;
21 en[tot]=y;
22 }
23
24 void dfs(int x)
25 {
26 int k,i;
27 sign++;
28 low[x]=sign; dfn[x]=sign; //x根的时间戳,x的时间戳
29 top++;
30 sta[top]=x; insta[x]=true; //sta[top]表示栈顶;insta[x]=true 是x在栈中的标记
31 k=first[x]; //枚举从x出发的第一条边
32 while(k!=0) //枚举从x出发的所有边
33 {
34 i=en[k]; //对面顶点
35 if(dfn[i]==0) //时间戳为0,没有搜索过
36 {
37 dfs(i); //从i出发继续搜索
38 if(low[i]<low[x]) low[x]=low[i]; //更新x的根的时间戳(缩小)
39 }
40 else //如果i搜索过
41 {
42 if((insta[i]) && (dfn[i]<low[x])) low[x]=dfn[i]; //如果i还在栈中,更新x的根的时间戳(缩小)
43 }
44 k=next[k]; //从x出发的下一条边
45 }
46 if(low[x]==dfn[x]) //如果从x出发的所有边都枚举了,并且x根的时间戳就是自己的时间戳,说明x是一个强连通分量的根
47 {
48 sum++; //累加强连通分量数量
49 i=sta[top]; //得到栈顶的顶点编号
50 while(i!=x) //依次出栈
51 {
52 id[i]=sum; //得到i点所属强连通分量
53 insta[i]=false; //出栈标记
54 top--;
55 i=sta[top]; //新的栈顶位置
56 }
57 top--; //x出栈
58 id[x]=sum; //得到x点所属强连通分量
59 insta[x]=false; //出栈标记
60 }
61 }
62
63 int main()
64 {
65 freopen("tarjan.in","r",stdin);
66 freopen("tarjan.out","w",stdout);
67 cin>>n>>m;
68 for(i=1;i<=m;i++)
69 {
70 cin>>a>>b;
71 Add(a,b);
72 }
73
74 memset(dfn,0,sizeof(dfn));
75 sum=0; sign=0;
76 for(i=1;i<=n;i++)
77 if(dfn[i]==0) dfs(i);
78
79 cout<<sum<<endl; //输出强联通的个数
80 for(i=1;i<=n;i++)
81 cout<<i<<" 属于第 "<<id[i]<<" 个强连通分量"<<endl;
82 return 0;
83 }