对tarjan的一个经典思考
本文章由此文章基础进行思考为什么,以下两份代码可以互换。
for (int i = head[u]; i ; i = G[i].next){
int v = G[i].v;
if (!dfn[v]){
tarjan(v); //说明v还未在栈中
low[u] = min(low[u], low[v]);
}
else if(!scc[v]){
low[u] = min(low[u], dfn[v]);
}
}
}
for (int i = head[u]; i ; i = G[i].next){
int v = G[i].v;
if (!dfn[v]){
tarjan(v); //说明v还未在栈中
low[u] = min(low[u], low[v]);
}
else if(!scc[v]){//看这里
low[u] = min(low[u], low[v]);
}
}
先说结论
- 在强连通分量可以写成第二份代码。
- 在边双连通分量可以写成第二份代码。
- 在点双的时候只能写成第一份代码。
为什么强连通分量可以互换?
在进行求解时我们最关心的是
如果
如果你在使用的是第二份代码当
因此根据性质按照第二份代码的
注意:
虽然经过证明可以互换但是如果要严格符合
为什么边双连通分量可以互换?
先回顾怎么判断一条边是否为桥,如果是桥那么必须满足
在边双连通分量中我们关心的是边的连通性问题。如果有一条从
若我们认为第二份代码是正确的我们就认为了
因为我们是在无向图中使用边双连通分量而且我们又没有路径可以让一个节点不经过父节点直接到祖先节点形成环。
如果
为什么点双连通分量不可以互换?
假设
先给出反例再给出证明。
反例:
进行第二份代码的模拟,先处理
在
错误原因
算法会认为
正确做法
如果使用第一份代码的写法,对于
总结
强连通分量具有传递性,只要在同一个强连通块内,值传得更小不影响根的判定。在边双连通分量中,只要能回到父亲节点的上面,该边就不是桥。传递更小的值依然满足点可以回到父亲节点之上的祖先节点。点双连通分量不可以是因为第二份代码的