- 若两顶点间至少存在一条路径,则称两个顶点强连通。
- 若有向图G中每两个顶点都强连通,则称G为强连通图。
- 非强连通图中的极大强连通子图称为强连通分量。
- Tarjan算法本质上是一种dfs。
- dfn[i]:dfs时被遍历的次序(时间戳)。
- low[i]:最早能回溯到的栈中的点的时间戳。
- stack[i]:判断i点是否在栈中。
- dindex:时间戳,stop:栈顶。
- 强连通分量中的点在栈中必定是连续一段。如果一个点x无法回溯到在它之前且在栈中的点,假设它的头顶上还有点,这些点的low值为x或者连接点(连接的连接…)的low为x(如果不是,1.是自己,在此之前已经弹出;2.是其它栈中点,首先不会是在x与它之间点y,因为y会比x更早被判断弹出(low[y]=dfn[y]),关于y的其它情况同上同下,如果是在x底下,那"x无法回溯到在它之前且在栈中的点"这一条件就不成立了)。这一切都源于tarjan算法本质为dfs!
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/d7d7c6306addc0bdc4db23238e87426d.png)
- 如果判断条件改为改成low[x]<low[v],更新改为low[x]=low[v],则上述证明中只有“low值为x”这一种情况。
- tarjan算法
void tarjan(int x)
{
dfn[x]=low[x]=++dindex;
instack[x]=true;
stap[++stop]=x;
for(int i=last[x];i;i=e[i].next)
{
int v=e[i].v;
if(!dfn[v])
{
tarjan(v);
low[x]=min(low[x],low[v]);
}
else if(instack[v]&&low[x]>dfn[v])
low[x]=dfn[v];
}
int j;
if(dfn[x]==low[x])
{
bcnt++;
do{
j=stap[stop--];
belong[j]=bcnt;
instack[j]=false;
powe[bcnt]+=dian[j];
}
while(j!=x);
}
}
- 将缩点完成后的DAG图练成一个强连通图:假设入度为零的点数为a,出度为零的点数为b,所需要的最小边数为max(a,b);若原图已经强连通,所需要的边数为0.
- tarjan给出了反拓扑序,不需要再额外topsort。