tarjan相关
tarjan求强连通分量
思想
普通的就是用来找有向图的强连通分量的
也就是在一个有向图中找一个尽可能大的图使其中的每一个点都可到达图中其他任意一点
这个东西可以时间一遍求出
对于图的序,如果有一条有向边指向已遍历过的点,那么这个点到它的当前这个儿子节点形成强连通
就像这样,形成强连通
但是只是强连通而已,不一定是强连通分量
如果一个节点的子孙有指向它的祖先节点的边,那么一定可以形成一个更大的强连通图
换句话说,如果一个节点的子孙没有指向它的祖先的边、只有指向它的边,那么这个点和它的子孙构成强连通分量
就像这样,蓝色的是强连通图,红色的却是强连通分量
那么我们只需要知道一个节点的子孙中有没有连回它祖先就可以了
那么就用一个栈记录一下
具体实现
具体实现要弄几个数组来搞
-
表示点在中是第几个被遍历到的
-
表示点与它的子孙节点中,最小的值
-
表示当前所有可能构成强连通分量的点
-
表示点是否在中
那么一个过程是这样的
-
首先,并把入栈
-
找能到达的所有点,如果没有访问过,那就该点,并把取两者的
-
如果访问过且该点在栈中那么也取两者的
-
最后如果,说明子孙节点和构成强连通分量了,给它们全染上同一种颜色就好了
-
为什么这么做的原因我不想说
code
O3 inline void tarjan(ll x)
{
dfn[x]=low[x]=++tot;
bz[x]=1,stack[++top]=x;
rep(i,x)
{
if (!dfn[tov[i]])
{
tarjan(tov[i]);
low[x]=min(low[x],low[tov[i]]);
}
else
{
if (bz[tov[i]])low[x]=min(low[x],low[tov[i]]);
}
}
if (dfn[x]==low[x])
{
color[x]=++sum,bz[x]=0;
while (stack[top]!=x)
{
color[stack[top]]=sum;
bz[stack[top--]]=0;
}
--top;
}
}
tarjan缩点
如果用缩点,相当于把某个强连通分量里的点的权值加起来或什么的,看成一个超级点
做完以后整张图通常是一棵树或是一个
这个思想比较重要
具体的自己手玩