https://blog.csdn.net/justlovetao/article/details/6673602
二、Tarjan算法(有向图的缩点)
1、内容:Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。
2、主要过程:
(1)每个点都有两个参数:DFN[ ],表示搜索次序编号,就是第几次被搜索到(时间截)
LOW[ ],表示每个节点在这个树中最小子树的根(即为u或者u的子树能回溯到的最早的栈中的节点)。
(2)搜索过程:
A、数组初始化:每次搜索到节点U时,DFN(u)为结点u的搜索次序编号
B、堆栈:将u入栈
C、更新Low(u):如果(u,v)中v不在栈中,Low(u)=min(Low(u),Low(v));
如果(u,v)为后向边(与dfs方向相反)或者横向边(v在栈中),Low(u)=min(Low(u),DFN(v));
D、全部遍历完成后,如果Low(u)==DFN(u),则将栈中节点全部弹出,这些元素构成一个强连通分量。
#include<bits/stdc++.h>
using namespace std;
const int N=100;
int head[N],instack[N],belong[N],dfn[N],low[N],sstack[N];
int cnt,index,top,bcnt,n,m;
struct edge{
int v,next;
}e[N];
void add(int u,int v)
{
e[cnt].next=head[u];
e[cnt].v=v;
head[u]=cnt++;
}
void tarjan(int u)
{
dfn[u]=low[u]=++index;
instack[u]=1;
sstack[++top]=u;
for(int i=head[u];i!=-1;i=e[i].next){
int v=e[i].v;
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}else{
if(instack[v]&&dfn[v]<low[u])
low[u]=dfn[v];
}
}
int j;
if(dfn[u]==low[u]){
bcnt++;
do{
j=sstack[top--];
instack[j]=0;
belong[j]=bcnt;
}while(j!=u);
}
}
void init()
{
cnt=top=bcnt=index=0;
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(head,-1,sizeof(head));
}
int main()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
init();
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
}
for(int i=1;i<=n;i++){
if(!dfn[i])
tarjan(i);
}
for(int i=1;i<=n;i++){
printf("%d ",belong[i]);
}
}