无向图连通分量:

即可。

有向图强连通分量:

中记录每个结点能到达的最前祖先,并入栈;若某个结点有 ,则当前栈顶到 是一个强连通分量。

缩点:

有些一般图的问题可以把一个强连通分量视作一个点,

然后转换成 上的问题,就可以用拓扑排序解决。

注意,缩点后需要对每个得到的强连通分量重新加边。

例题:

#10093. 「一本通 3.5 练习 1」网络协议

第一问只需缩点后求入度为 点个数即可。

第二问稍有意思。

缩点后,第二问即问向一个 中加多少边可使其强连通。

情况1: 如果只有一个点,那么图已经强连通,

情况2:

否则设图中入度为 的点有 个, 出度为 的点有 个,则

这是因为:不妨设 。则每个出度为 的点都要能相互到达,至少需要 条边。

然后我们可以给出一个用 条边满足要求的例子,即 可取到等号,那么答案就是

此技巧解组合数学题常用。

构造方法即为对每一个出度为 0 的向入度为 0 的点连边,

并保证每个入度为 0 的点都被出度为 0 的点相连。

至于孤立点,从其引一条边到入(出)度为 0 的点,则这个孤立点成为新的入(出)度为 0 的点。

#10096. 「一本通 3.5 练习 4」抢掠计划

缩点求给定起点到某些可以结束点的最长路。

有个坑:缩点只能从缩起点可达的点。不然会导致拓扑的过程中有些起点到不了的点不被访问,因而它连的点入度不能变成 ,就不能被加进队列。

无向图的割点和桥

割点是指去掉这个点,图的连通块数量会 的点,

而桥指去掉这个边,图的连通块数量会 的边。

如果我们用 表示 所能到达的 序最小的祖先,那么

是割点 存在 的儿子

到儿子 的边是桥

注意:根节点是割点的条件是儿子数大于

这里写代码的时候有个注意点:

        if(!dfn[v])
    {
            child ++;
        dfs(v, u);
        pre[u] = min(pre[u], pre[v]);
            if(pre[v] > dfn[u]) isbrige[i] = isbrige[i ^ 1] = true;
            if(pre[v] >= dfn[u] && fa != 0) iscut[u] = true;
    }    
    else if(v != fa)
            pre[u] = min(pre[u], dfn[v]);//这里不能用 pre[v] 代替 dfn[v]。

原因:

由于此处是一张无向图,我们又双向建了边,导致节点可以回溯到它的父节点;

而如果从它的父节点或其父节点的另一棵子树上有向上很多的返祖边,

这时把子节点的 值赋为父节点的 ,就可能导致其 其父节点 其父节点

从而使本该是割点的点被忽视了。

例题

#10101. 「一本通 3.6 练习 2」嗅探器

求给定两点路径中的关键点。

关键点显然是割点。

我们从起点开始 , 遇到一个割点,就判断 是否 ,如果满足,那么 就是一个关键点。

#10103. 「一本通 3.6 练习 4」电力

求一个图删除一个点之后,联通块最多有多少。

对于每个割点,记录它被删除后会多出多少连通块即可。

对于根节点,多出的就是

对于非根节点,多出的就是满足 的儿子数。

小坑:图中可能没有割点,此时如果没有边,答案就是 ,如果有边,答案就是

#10104. 「一本通 3.6 练习 5」Blockade

求去掉一个点后有多少对点不可达。

如果去掉 是根,若其有儿子,儿子树大小 , 则答案为

如果去掉 不是根,设其有若干儿子,例如二个儿子,儿子树大小 不能通过非树边到达 的祖先,那么这二个儿子,与其他儿子和 祖先这三个团两两不可达,答案是

其中

边双连通分量 - 边双缩点

一个图边双连通是指任意两个点都可以通过两条边不重复的两条路径到达。

显然,桥不属于双连通分量,不是桥的任一边属于一个双连通分量。

那么我们先求出所有桥,再遍历一遍整个图,并且不走桥边,那么遍历到的每一个连通块就是一个双连通分量。

如果我们将 缩成一个点,那么最终的图就是一个只含桥和 的无根树。

例题:

#10098. 「一本通 3.6 例 1」分离的路径

求最少新加几条边能让原图边双连通。

图中已有的 中显然不会加边。所以我们可以将其缩成一个点。

问题转化为边双缩点后的无根树中,加几条边可以双连通。

显然每个叶子节点都要被连边,那么

又每次给两叶子结点连边,如果叶子数为奇数则向非叶子结点或已经连过边的叶子节点连边,那么得到的图边双连通,且用来恰 条边。

故答案就是

点双连通分量 - 点双缩点

一个图点双连通是指任意两个点都可以通过除起点终点外的点不重复的两条的路径到达。

和边双连通不同的是,一个割点可能属于多个

就属于两个不同的

为了求出 ,我们需要在 的过程中维护一个栈。

当一个点第一次被访问时,我们将它入栈。而当割点判定法则成立时,无论 是否为根,都要从栈顶不断弹出节点直到 节点被弹出,这些被弹出的节点包括 节点一起构成一个

如果把所有的 看作点,保留原图的割点,如果割点 属于 , 则给 连边。

得到的新图是一颗无根树。

例题

#10099. 「一本通 3.6 例 2」矿场搭建

放置若干出口,使得任一点被摧毁后别的点都与至少一个出口相连。

对于每个 , 若它只含一个割点,那么那个割点被摧毁后这个 中一定含有一个出口。

所以对于每个只含一个割点的 , 都建立一个出口。

而将原图点双缩点可以看出,这样做实际是对每个叶子建立出口。

这样建立以后,图已满足要求,故答案就是恰含一个割点的 的个数。

坑点:可能原图不含割点,此时整个图就是一个 , 需要建立两个出口。

参考资料:

代码人生-边双、点双缩点

分离的路径

[Tarjan系列] Tarjan算法求无向图的双连通分量