#include<iostream> using namespace std; #define MAXN 10000//最多的点数 #define MAXM 10000//最多的边数 struct Node { int to; int next; }graph[MAXM]; int head[MAXN]; int n, m;//顶点数,边数 int low[MAXN], dfn[MAXN];//low[i]表示能回溯到的最小节点,dfn[i]表示访问的顺序 int belong[MAXN];//belong[i]表示i属于哪一个强连通分支 bool instack[MAXN];//instack[i]表示是否在堆栈中 int stack[MAXN]; int index, num, top;//num表示有几个强连通分支 /**************************** insert()函数 输入:两个节点的标号 输出:无 功能是用链接表建立图 *****************************/ int cnt; void insert(int u, int v) { graph[cnt].to = v; graph[cnt].next = head[u]; head[u] = cnt++; } inline int min(int a, int b) { if(a<b) return a; else return b; } /*************************** tarjan()函数 输入:要访问的节点 输出:无 功能:寻找强连通分量 ****************************/ void tarjan(int id) { int i, j, e; dfn[id] = low[id] = ++index; instack[id] = true; stack[top++] = id; for(i = head[id]; i!=-1; i = graph[i].next) { e = graph[i].to; if(!dfn[e])//如果未访问的话 { tarjan(e); low[id] = min(low[id],low[e]);//更新low值 } else if(instack[e]) low[id] = min(low[id], dfn[e]); } if(dfn[id] == low[id])//寻找强连通分支的根 { num++;//强联通分支的数量 do { j = stack[--top]; instack[j] = false; belong[j] = num; }while(j!=id); } } int main() { freopen("in.txt", "r", stdin); int i, u, v, j; while(scanf("%d %d", &n, &m)!=EOF) { for(i=0; i<=n; i++)//初始化 { head[i] = -1; dfn[i] = 0; low[i] = 0; instack[i] = false; } index = cnt = num = top = 0; for(i=0; i<m; i++) { scanf("%d %d", &u, &v); insert(u, v); } for(i=1; i<=n; i++) if(!dfn[i]) tarjan(i); printf("总共有几个强连通分支:%d/n",num); for(i=1; i<=num; i++) { printf("第%d个强连通分支是:", i); for(j=1; j<=n; j++) if(belong[j] == i) printf("%d ",j); printf("/n"); } } return 0; }