Tarjan 算法
强连通分量
若图 $G$ 中存在一个子图 $G'$
图的强连通分量可以考虑使用 $\rm Tarjan$ 算法求解
$\rm Tarjan$ 算法的思想是这样的
时间复杂度 $\Theta(n+m)$
参考代码
void Tarjan (int u) {
dfn[u] = low[u] = ++tix, Sta[++top] = u;
for (int i = last[u]; i; i = Next[i])
if (!dfn[to[i]]) Tarjan(to[i]), low[u] = min(low[u], low[to[i]]);
else if (!SCC[to[i]]) low[u] = min(low[u], dfn[to[i]]);
if (dfn[u] == low[u]) {
SCC[u] = ++id;
while (Sta[top] != u) SCC[Sta[top--]] = id;
top--;
}
}
点/边双连通分量
如果在 $\rm dfs$ 树上
当然
遍历的时候要记得判掉父子边
和判断割点的方法几乎一模一样
判断割边的时候根节点不需要特殊考虑
时间复杂度 $\Theta(n+m)$
参考代码
void Tarjan (int u, int rt) {
dfn[u] = low[u] = ++tix;
int son = 0;
for (int i = last[u]; i; i = Next[i]) {
if (!dfn[to[i]]) {
son++, Tarjan(to[i], rt);
low[u] = min(low[u], low[to[i]]);
if (low[to[i]] >= dfn[u] && u != rt) cut[u] = true;
}
low[u] = min(low[u], dfn[to[i]]);
}
if (u == rt && son > 1) cut[u] = true;
}
经典例题
[国家集训队] 稳定婚姻
首先在夫妻之间连有向边 $B_i\to G_i$
可以发现
于是我们使用 $\rm Tarjan$ 算法求强连通分量
时间复杂度 $\Theta(n+m)$
[ZJOI2007] 最大半连通子图
首先缩点
然后将 $\rm DAG$ 画出来发现最大半连通子图一定是某条从无入度结点到无出度结点的链
需要注意的是
时间复杂度 $\Theta(n+m)$
[HNOI2012] 矿场搭建
先把个点和点双连通分量处理出来
- 若该点双无割点
则需要建两个出口, 。 - 若该点双有一个割点
则需要在这个点双内建一个出口, 且不能建在割点上, 。 - 若该点有两个以上割点
则不需要建出口, 因为一定可以从某个割点跑出去, 。
方案数直接乘法原理计算即可
时间复杂度 $\Theta(n+m)$
[HAOI2010] 软件安装
可以发现这是一棵基环外向树
时间复杂度 $\Theta(nm)$