作者:Heartquakes,发表于 Sat Jul 20 2024。
在有向图中,选取一个点集 $S$,若对于 $S$ 中的任意两点 $u, v$,都满足 $u$ 可以到达 $v$,则称 $S$ 是强连通的。
强连通分量是图中一个极大的强连通的点集。
性质:把一个有向图通过强连通分量缩点后,新的图是一个 DAG.
在无向图中,求解连通分量只需要按照 $1$ 到 $n$ 的顺序依次考虑每个点。 考虑到 $i$ 点时,如果 $i$ 点未被访问过,就说明找到了一个新的连通分量,从 $i$ 点开始 DFS 即可找到i所在的连通分量。
在有向图中,上述算法不成立。
假设 $A$ 和 $B$ 是两个不同的强连通分量,且 $A$ 可以到达 $B$,那么只有先访问 $B$,再访问 $A$,才能使得上述算法成立。 也就是说,遍历顺序要保证 $B$ 中至少有一个点排在所有 $A$ 中的点之前。 考虑缩点后得到的 DAG,每次应访问出度为 $0$ 的点,即按照拓扑序的逆序访问缩点后的所有节点。
Kosaraju 算法的思想:
因为把边反向与否不改变强连通分量,所以得到一个简化的算法:
#include <bits/stdc++.h>
using namespace std;
bool vis[N];
vector<int> g[2][N];
stack<int> stk;
void dfs1(int u)
{
vis[u] = 1;
for(auto v : g[0][u])
if(!vis[v]) dfs1(v);
q.push(x);
}
void dfs2(int u, int id)
{
vis[u] = 0, bel[u] = id;
for(auto v : g[1][u])
if(vis[v]) dfs2(v, root);
}
int main()
{
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
for(int i = 1; i <= n; i++)
if(!vis[i]) dfs1(i);
while(!stk.empty())
{
int u = stk.top(); stk.pop();
if(vis[u]) dfs2(u, ++idx);
}
return 0;
}
一张图的 DFS 树是在对其进行 DFS 时,所经过的所有有效边形成的树结构。
在构造题中,通常我们用到的是无向图的 DFS 树。
无向图的 DFS 树满足所有非树边都是返祖边。
一个无向连通图边双连通,当且仅当对于任意两个点,存在两条不相交的路径。
边双连通分量是图中一个极大的边双连通的点集。
定义割边为:在无向图中,该边所在连通块不再连通的边。 边双连通的定义中,“存在两条不相交的路径”显然等价于“如果无论删去哪条边都不能使它们不连通”,故一个无向连通图边双连通的充要条件是没有割边。
一个无向图边双缩点后是一棵树,所有树边是割边。 (若缩点后不是一颗树,说明还存在环,则环上所有的点在一个边双内,这与边双连通分量“极大”的定义矛盾。)
由【3.1. 定义&性质】,求出所有边双连通分量只需求出所有割边,由割边断开后得到的一个连通块就是一个边双连通分量。
取原图的 DFS 树,只有树边有可能是割边。
一条非树边(由【2. DFS 树】的性质知,只可能是返祖边)会覆盖掉一条链上的树边,这些树边就会被 ban 掉,使用树上差分(或树剖)维护,剩下的边就是割边。
一个神秘的 MST 求法。
维护一些连通块(初始都是单点),并进行若干轮连边。
每一轮中,找到每个连通块连向其它连通块的最小边(需要做不等离散化,以边权为第一关键字,以边的编号为第二关键字)并连上,这一条边一定会在 MST 中。 (可以根据 Kruscal 的流程证明。)
每轮连通块数量至少减半,最多进行 $O(\log n)$ 轮连边。 最劣时间复杂度 $O((n + m) \log n)$.
Boruvka 算法适合用来求完全图(或非常稠密图)的 MST.
给定一张 $n$ 个点 $m$ 条边的无向图和 $q$ 组有向点对 $(s, t)$。 询问是否存在使得所有 $s$ 都能到达 $t$ 的无向图中每条边的定向方案。 $n,m,q \le 2 \times 10^5$.
有一个显然的结论:
在边双连通分量中可定向,使得内部构成强连通。
只需取边双中的 DFS 树,使树边向下,非树边向上即可。
则在本题中,若 $s, t$ 在同一边双,则不必考虑(一定可以)。 那么只需考虑 $s, t$ 在不同边双的情况。
考虑将原图按边双缩点成一颗树。 对于每个询问 $s, t$,在树上的路径一定为 $s$ 到根之间向上、根到 $t$ 之间向下。
可以使用树链剖分+线段树区间覆盖来做,做的过程中 check 当前要定向的边中是否有边已经被定了相反的方向。
给定一个无向连通图和正整数 $k$,求一个大小为 $\lceil \frac{k}{2} \rceil$ 的独立集或大小不超过 $k$ 的环(求出任意一个即可)。
首先找到图中的最小环。
问题转化为如何求最小环。
对于一条非树边 $(u, v)$,定义 $w_{u, v} = |dep_v - dep_u|$. 找到图中 $w$ 最小的非树边,它和 $u, v$ 之间的所有树边构成最小环。
给定一张 $n$ 个点 $m$ 条边的无向连通图,以及一个整数 $k$,保证每个点度数 $\ge 3$,你需要找到一个至少有 $\lceil \frac{n}{k} \rceil$ 个点的路径,或者找出 $k$ 个环,其中每个环的环长都不是 $3$ 的倍数,且每个环中至少有一个点在这 $k$ 个环里只出现一次。
任取一棵 DFS 树。
给定一个 $n$ 个点、$m$ 条边的无向连通图,以及三个整数 $a, b, c$,满足 $a + b + c = n$,你需要将 $n$ 个点分成三个集合 $A, B, C$,大小分别为 $a, b, c$,使得其中至少两个集合是连通的 (集合中的任意两个点能只经过该集合内的点互相到达),或者报告无解。
不妨设 $a \le b \le c$,则让集合 $A, B$ 连通的限制一定是最松的。
考虑原图是树的情况。我们想找到一条边,让它两侧的点数分布尽量均匀。
考虑重心,找到所有以重心为根的子树中最大的一个,连接这棵子树与重心的边即为该边。有解当且仅当子树 $size \ge a$.
Copyright © 2024 LVJ, Open-Source Project. 本站内容在无特殊说明情况下均遵循 CC-BY-SA 4.0 协议,内容版权归属原作者。