参考博客:比较详细。
http://www.byvoid.com/blog/scc-tarjan/
算法伪代码描述:Tarjan(root)
1、初始化 def , low[], map[][]
2、stack<- root // 将 root 节点入栈
3、 对 与 root 相连的每个 节点 p 如果 p 在 stack 中 那么 low[root] = min(low[root], def[p]);并且 call Tarjan(p)
4、 如果对 与 root 相连的每个 节点 p 如果 p 不在 stack 中 那么 low[root] = min( low[p], low[root])
5 、当 low[root] = def[roo] 时,输出栈里 在 root 之上的 所以 元素 为一个连通分量
6、继续搜索,直到所有的节点被遍历
代码如下:
1:邻接矩阵存储
#include <iostream>
#include<stack>
#include<vector>
using namespace std;
#define V 100
int map[V][V]; // 存放地图
int def[V]; // def[i] 记录 i 节点的访问时间
int low[V]; // 记录 i 节点连通分量 所在集合的能追朔到的最小 def
bool instack[V];// 标记 i 是否在 堆中, 在 为 1 , 不在 为 0
int count ;// 连通分量的个数
int temp;//
vector<int> result[V];// 保存连通分量的结果集
stack<int> stack_v ;
int index = 0;
int min ( int a, int b){
return a>b?b:a;
}
void tarjan ( int map[][V], int def[V], int low[V],int root, int n){// n 表示节点的个数
instack[root] = true;
def[root] = low[root] = ++index;
stack_v.push(root);
//假设初始化已经完成
// 从根节点 root (也就是 入度为 0 的节点进行 搜素)
for ( int i = 1; i <= n; i++){
if( map[root][i] == 1){// 表示 root 和 节点 i 连通
if( def[i] == 0 ){ // 表示 i 点还没有被访问
tarjan(map,def,low,i,n);
low[root] = min( low[root],low[i]);
}
if( instack[i] == true){ // 如果 i 节点在 栈中
low[root] = min( low[root], def[i]);
}
}
}
if( def[root] == low[root] ){
count ++;
do{
temp = stack_v.top();
stack_v.pop();
instack[temp] = false;
cout<< temp<<" ";
result[count].push_back(temp);
}while(temp != root);
cout<<endl;
}
}
int main(void){
int n ,e, x, y;// n 为顶点个数, e 为表的个数
cin>>n>>e;
for( int i =0; i < e; i++){
cin>>x>>y;
map[x][y] = 1;
}
tarjan(map,def,low,1,n);
cout<<count<<endl;
return 0;
}
2:邻接表存储
#include<iostream> #include<vector> using namespace std; #define M 2000 //题目中可能的最大点数 int STACK[M],top=0; //Tarjan 算法中的栈 bool InStack[M]; //检查是否在栈中 int DFN[M]; //深度优先搜索访问次序 int Low[M]; //能追溯到的最早的次序 int ComponetNumber=0; //有向图强连通分量个数 int Index=0; //索引号 vector <int> Edge[M]; //邻接表表示 vector <int> Component[M]; //获得强连通分量结果 int min(int a, int b){ return a>b?b:a; } void Tarjan(int i) { int j; DFN[i]=Low[i]=Index++; InStack[i]=true; STACK[++top]=i; for (int e=0;e<Edge[i].size();e++) { j=Edge[i][e]; if (DFN[j]==-1) //如过点 j 还没有被访问 { Tarjan(j); Low[i]=min(Low[i],Low[j]); } else if (InStack[j]) // 如果点j 在 Low[i]=min(Low[i],DFN[j]); } if (DFN[i]==Low[i]) { cout<<"TT "<<i<<" "<<Low[i]<<endl; ComponetNumber++; do { j=STACK[top--]; InStack[j]=false; Component[ComponetNumber].push_back(j); } while (j!=i); } } void solve(int N) //此图中点的个数,注意是0-indexed! { memset(STACK,-1,sizeof(STACK)); memset(InStack,0,sizeof(InStack)); memset(DFN,-1,sizeof(DFN)); memset(Low,-1,sizeof(Low)); for(int i=0;i<N;i++) if(DFN[i]==-1) Tarjan(i); } /* 此算法正常工作的基础是图是0-indexed的。 */ int main() { Edge[0].push_back(1);Edge[0].push_back(2); Edge[1].push_back(3); Edge[2].push_back(3);Edge[2].push_back(4); Edge[3].push_back(0);Edge[3].push_back(5); Edge[4].push_back(5); int N=6; solve(N); cout<<"ComponetNumber is "<<ComponetNumber<<endl; for(int i=0;i<N;i++) cout<<Low[i]<<" "; cout<<endl; for( i=0;i<N;i++) { for(int j=0;j<Component[i].size();j++) cout<<Component[i][j]; cout<<endl; } return 0; }