Tarjan注意事项
割点判断 $low_v \ge dfn_u$
割桥 $low_v > dfn_u$
缩点/强连通分量,更新要判断点是否在栈中
点双,多看看。
求出所有的桥以后,把桥边删除,原图变成了多个连通块,则每个连通块就是一个边双连通分量。先用 Tarjan 算法标记处所有的桥边,再对整个无向图 DFS 一遍(遍历的过程中不访问桥边),划分出每个连通块。
割点
void tarjan(int u, int f)
{
dfn[u] = low[u] = ++tim;
int child = 0;
FR
{
if (!dfn[v])
{
child++;
tarjan(v, u);
low[u] = min(low[u], low[v]);
if (u != f && low[v] >= dfn[u])
IsDi[u] = 1;
if (u == f && child > 1)
IsDi[u] = 1;
}
low[u] = min(low[u], dfn[v]);
}
}
割桥
void tarjan(int u , int f) {
dfn[u] = low[u] = ++tim;
FR {
if(v == f) continue;
if(!dfn[v])
{
tarjan(v , u);
low[u] = min(low[u] , low[v]);
if(low[v] > dfn[u]) ans[++tot] = mp(min(u , v) , max(u , v));
}
low[u] = min(low[u], dfn[v]);
}
}
缩点
void tarjan(int u)
{
dfn[u] = low[u] = ++tim;
st[++top] = u, ins[u] = 1;
FR
{
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(ins[v])
low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u])
{
++cot;
int y;
do
{
y = st[top--], ins[y] = 0;
c[y] = cot, scc[cot].push_back(y);
dga[cot] += val[y];
} while (u != y);
}
}
点双联通分量
void tarjan(int u, int f) {
int cnt = 0;
dfn[u] = low[u] = ++tim;
st[++top] = u;
for(int i = head[u]; i; i = e[i].next) {
int v = e[i].to;
if(v == f) continue;
if(!dfn[v]) {
cnt++;
tarjan(v, u);
low[u] = min(low[v], low[u]);
if(low[v] >= dfn[u]) {
int t;
++tot;
while(st[top + 1] != v) DSS[tot].push_back(st[top--]);
DSS[tot].push_back(u);
}
} else low[u] = min(low[u], dfn[v]);
}
if(!f && !cnt) DSS[++tot].push_back(u), top--;
}

浙公网安备 33010602011771号