本蒟蒻第一次写博客,不喜勿喷
什么是 Tarjan 算法呢?
让我们来看一张有向图:
首先,我们要知道 dfs序 是什么(应该都知道吧)。
顾名思义,dfs序 就是一张图在进行 dfs 时所经历的点的先后排序。
详见:dfs序(基础讲解)_不牌不改的博客-CSDN博客_dfs序
(借用,如有侵权请联系删除)。
再一个,我们要知道 强联通, 强项通图, 强联通分量 是什么。
强联通:强连通是指一个有向图G中,任意两点v1、v2间存在v1到v2的路径, 以及v2到v1的路径。
强连通图: 如果 在一个有向图G中,每两个点都强连通,我们就叫这个图强连通图。
强连通分量:有向图的所有强连通子图。
tarjan算法,用dfs就是因为它将每一个强连通分量作为搜索树上的一个子树。
两个参数:
1,dfn[]作为这个点搜索的次序编号,简单来说就是 第几个被搜索到的。
2,low作为每个点在这颗树中的,最小的子树的根,每次保证最小。如果它自己的low[]最小,那这个点就应该重新分配,变成这个强连通分量子树的根节点。
而为了存储整个强连通分量,这里挑选的容器是,堆栈。每次一个新节点出现,就进站,如果这个点有 出度 就继续往下找。直到找到底,每次返回上来都看一看子节点与这个节点的low值,谁小就取谁,保证最小的子树根。如果找到dfn[] == low[]就说明这个节点是这个强连通分量的根节点。最后找到强连通分量的节点后,就将这个栈里,比此节点后进来的节点全部出栈,它们就组成一个全新的强连通分量。
上代码:
void tarjan(int u) {
dfn[u] = low[u] = ++ num;
stack[++top] = u;
ins[u] = 1;
for (int i = head[u]; i; i = edge[i].nxt) {
int v = edge[i].v;
if(!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(ins[v]) {
low[u] = min(low[u], loe[v]);
}
}
if(dfn[u] == low[u]) {
cnt++;
int v;
do {
v = stack[top]--;
ins[v] = 0;
c[v] = cnt;
scc[cnt].push_back(v);
} while(u != v);
}
}