[Tarjan算法]
定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#define CLR(a,b) memset(a,b,sizeof(a))
#define Min(a,b) a>b?b:a
using namespace std;
const int I=150;
int Bcnt; //记录找到的强连通分量的标号
int Dindex; //图中结点标号
int instack[I]; //标记图中结点是否在栈中
int path[I][I]; //记录强连通分量之间的路径
int in[I],out[I]; // 缩点后,记录每个强连通分量的入度和出度
int DFN[I]; // DFN[u]: 记录结点u搜索的次序编号
int LOW[I]; //LOW[u]: 表示,在栈中搜索u以及u的子树的所有结点,能够找到的最早的次序编号。
int Belong[I]; //Belong[u]: 记录结点结点u属于哪一个强连通分量
stack<int> Stack;
struct node //存储边的信息
{
int to;
node *next;
};
node *edge[I];
void tarjan(int u) //targan算法,求强连通分量
{
DFN[u]=LOW[u]=++Dindex; //为结点u标号
Stack.push(u); //结点进栈
instack[u]=1; //标记栈中结点
for(node *e=edge[u];e;e=e->next) //搜索与u结点相连的所有边
{
int v=e->to;
if(!DFN[v]) // 该点不在栈中
{
tarjan(v); //深搜
LOW[u]=Min(LOW[u],LOW[v]); //更新结点u的标号
}
else if(instack[v]) // 该点在栈中
LOW[u]=Min(LOW[u],DFN[v]); // 更新结点u的标号
}
if(DFN[u]==LOW[u]) //该结点是强连通分量的根
{
Bcnt++;
int j;
do
{
j=Stack.top();
instack[j]=0;
Stack.pop();
Belong[j]=Bcnt;
}while(u!=j);
}
}
void solve(int n)
{
CLR(DFN,0);
Bcnt=Dindex=0;
for(int i=1;i<=n;i++)
if(!DFN[i])
tarjan(i);
}