图论
网络流
- 反向边 — 改变之前的选择,顺便补充新流 / 交换不同流的去向
-
复杂度证明
- F F FF FF — O ( E m a x v ) O(E\,max\,v) O(Emaxv) ,特殊情形
- E K EK EK/ S A P SAP SAP(最短路增广)— O ( n m 2 ) O(nm^2) O(nm2) :每增广一次某边,增广路长度加2,即增广路条数 O ( n m ) O(nm) O(nm)。
-
d
i
n
i
c
dinic
dinic (多路增广) —
O
(
n
2
m
)
O(n^2m)
O(n2m) :单次增广
O
(
n
m
)
O(nm)
O(nm) — 当前弧变化
O
(
m
)
O(m)
O(m) 次;增广
O
(
n
)
O(n)
O(n) 次。
- 二分图匹配问题 / 边容量都为1、出/入边唯一的单位网络 中 — O ( m n ) O(m\sqrt n) O(mn) : O ( n ) O(\sqrt n) O(n) 次增广,单次 O ( m ) O(m) O(m) 。
- I S A P ISAP ISAP (将 d i n i c dinic dinic 改用 预处理+距离标号) — 与 d i n i c dinic dinic 类似。
- 预留推进 — O ( n 2 m ) O(n^2m) O(n2m) :每个点改高度标号 O ( n ) O(n) O(n) 次,每次可多增广 O ( m ) O(m) O(m) 次。
- H L P P HLPP HLPP(用堆选最高点推进)— O ( n 2 m ) O(n^2\sqrt m) O(n2m) :
最小割
- 最大流最小割定理 — 一个流 f 的任意割 cut(S,T) 满足 f 等于正负向割边流量差;最大流中 负向割边流量为0 – 正向的与割取等。 ---- baidu.com
- 无源汇最小割(全局最小割) — 划分点集 的最小删边代价
-
S
t
o
e
r
\bold{Stoer}
Stoer-
W
a
g
n
e
r
\bold{Wagner}
Wagner —
O
(
n
3
)
/
O
(
n
2
log
n
)
O(n^3)/O(n^2\log n)
O(n3)/O(n2logn) 。
- 依据:对于一对点 S,T,要么分居两集(此时 cut(S,T)=cut(G) ),要么两点在最小割同一集合(此时与 若割了(S,u)T 与u必不在同一联通块)。
- 得出做法:1.找到任意一对(S,T)的解。2.将 S、T 合并为一个点,回到步骤1。
- 步骤1:“排序”,使 ( { v 1 , ⋯ , v n − 1 } , { v n } ) (\{v_1,\cdots,v_{n-1}\},\{v_{n}\}) ({v1,⋯,vn−1},{vn}) 为 ( v n − 1 , v n ) (v_{n-1},v_{n}) (vn−1,vn) 最小割 — 任选一点作 v 1 v_1 v1 ,每次找到 f ( V , x ) f(V,x) f(V,x) 最大的 x 加到 V 中。
-
S
t
o
e
r
\bold{Stoer}
Stoer-
W
a
g
n
e
r
\bold{Wagner}
Wagner —
O
(
n
3
)
/
O
(
n
2
log
n
)
O(n^3)/O(n^2\log n)
O(n3)/O(n2logn) 。
竞赛图相关
- 定义:“有向完全图”。
- 性质 ----
- 图结构:强连通分量缩点后构成“链状”结构。
- 强连通分量中三元环存在性
- H a l m i t o n Halmiton Halmiton路径存在性 \ H a l m i t o n Halmiton Halmiton回路存在性(为强连通图时)。
- 分数序列判定( L a n d a u ′ s T h e o r e m Landau's \,Theorem Landau′sTheorem):序列合法充要条件 ∑ i ≤ k s i ≥ ( k 2 ) \sum_{i\leq k}s_i\geq\binom{k}{2} ∑i≤ksi≥(2k)
P r u f e r Prufer Prufer序列
- 定义:对有标号无根树不断摘取编号最小叶节点(剩下两个点),记录下每次删的点的父亲节点得到的长 n − 2 n-2 n−2 的序列即 P r u f e r Prufer Prufer序列。
- 构造:
- 堆 - O ( n log n ) O(n\log n) O(nlogn);单指针扫 O ( n ) O(n) O(n)。
- “翻译”:
- 每次确定一个叶节点。
- 复杂度同“构造”。
- 性质:
- P r u f e r Prufer Prufer序列与有标号无根树建立了双射。
- 点编号在序列中的出现次数 = 树中点度数 - 1.
- 应用:
- 有标号无根树 计数: n n − 2 n^{n-2} nn−2
- 图联通计数: n k − 2 ∏ i = 1 k s i n^{k-2}\prod_{i=1}^k s_i nk−2∏i=1ksi
矩阵树定理
-
D e f i n i t i o n Definition Definition:
- D D D、 D i n D^{in} Din、 D o u t D^{out} Dout 为图的度数矩阵; A A A 为图的边权矩阵。
- L L L、 L i n L^{in} Lin、 L o u t L^{out} Lout 为图的 Laplace 矩阵(亦称 Kirchhoff 矩阵)— L = D − A L=D-A L=D−A
- 生成树个数 t ( G ) t(G) t(G)
- M 0 M_0 M0 为 M M M 去掉一行得到的矩阵。
- 设 M M M为 n × m n\times m n×m 的矩阵。 M [ S ] M[S] M[S] 为,任取大小为 n 的集合 S ( ⊆ [ 1 , m ] ⋂ Z ) S(\subseteq [1,m]\bigcap Z) S(⊆[1,m]⋂Z),保留 M 的第 S i S_i Si 列得到的矩阵( n × n n\times n n×n)。
- L 0 L_0 L0 为 L L L 去掉 i 行 i 列得到的矩阵。
-
M a t r i x − t r e e T h e o r e m Matrix-tree \,\, Theorem Matrix−treeTheorem:
-
无向图: t ( G ) = det ( L 0 ) t(G)=\det(L_0) t(G)=det(L0).
-
证明思路:
-
首先,构造矩阵 M M M — n × m n\times m n×m , M i , j = [ e j = ( i , v ) ] − [ e j = ( u , i ) ] M_{i,j}=[e_j=(i,v)]-[e_j=(u,i)] Mi,j=[ej=(i,v)]−[ej=(u,i)].
有 M M T = L MM^T=L MMT=L.
然后,可以发现 det ( M 0 [ S ] ) = ± [ S 为 某 生 成 树 边 集 ] \large\det(M_0[S])=\pm[S为某生成树边集] det(M0[S])=±[S为某生成树边集]
最后,由 B i n e t − C a u c h y \bold{Binet}\!-\!\bold{Cauchy} Binet−Cauchy定理
det ( L 0 ) = ∑ S det ( M 0 [ S ] ) ⋅ det ( M 0 [ S ] T ) = t ( G ) \large\det(L_0)=\sum_S\det(M_0[S])\cdot\det(M_0[S]^T)=t(G) det(L0)=S∑det(M0[S])⋅det(M0[S]T)=t(G)
-
-
有向图:根向树, t ( G ) = det ( L 0 o u t ) t(G)=\det(L^{out}_0) t(G)=det(L0out);叶向树, t ( G ) = det ( L 0 i n ) t(G)=\det(L_0^{in}) t(G)=det(L0in) 。
-
根向树形式证明思路(与无向类似)(叶向树同理):
-
首先,构造矩阵 A , B A,B A,B, A i , j = [ e j = ( i , v ) ] − [ e j = ( u , i ) ] A_{i,j}=[e_j=(i,v)]-[e_j=(u,i)] Ai,j=[ej=(i,v)]−[ej=(u,i)], B i , j = [ e j = ( i , v ) ] B_{i,j}=[e_j=(i,v)] Bi,j=[ej=(i,v)].
有 A B T = L o u t AB^T=L^{out} ABT=Lout.
然后,可以发现,若 S 为某生成树边集, det ( A 0 [ S ] ) = det ( B 0 [ S ] ) \det(A_0[S])=\det(B_0[S]) det(A0[S])=det(B0[S]);
否则 det ( A 0 [ S ] ) ⋅ det ( B 0 [ S ] ) = 0 \det(A_0[S])\cdot\det(B_0[S])=0 det(A0[S])⋅det(B0[S])=0
最后,
det ( L 0 o u t ) = ∑ S det ( A 0 [ S ] ) ⋅ det ( B 0 [ S ] T ) = t ( G ) \large\det(L_0^{out})=\sum_S\det(A_0[S])\cdot\det(B_0[S]^T)=t(G) det(L0out)=S∑det(A0[S])⋅det(B0[S]T)=t(G)
-
-
拓展:把边权看作重边数,那么可以计算所有生成树的边权积的和 — 可用乘法原理理解。
-
关于 B i n e t − C a u c h y \bold{Binet}\!-\!\bold{Cauchy} Binet−Cauchy定理 的证明:
-
先证明: ∀ A , B , C ∈ { n o r d e r m a t r i x e s } \large \forall A,B,C\in\{n order \, matrixes\} ∀A,B,C∈{nordermatrixes}
-
-
-
应用:
- 除了简单的生成树计数,其实还可以把上述拓展应用于“多项式边权”,同样合法。
- 这有什么作用呢?可参考**「2020联合省选Day2T3作业题」— 这道题把边权设置为 A i x + 1 A_ix+1 Aix+1 ,那么行列式算出来一次项系数便为生成树边权和**。
- 另外,结合生成函数的特点,可以发现这个应用的更深层意义 — 幂指数标示了特殊边的选择次数。那么对有关有色边的生成树问题提供了较好的思路。当有多种颜色(
真是变态),就可以考虑多设几个变量 x,y,z,…
BEST定理
欧拉图上的欧拉回路计数。
∀
k
,
a
n
s
=
t
r
o
o
t
(
G
,
k
)
deg
(
k
)
∏
v
∈
V
(
deg
(
v
)
−
1
)
!
\large \forall k, ans=t^{root}(G,k)\deg(k)\prod_{v\in V}(\deg(v)-1)!
∀k,ans=troot(G,k)deg(k)v∈V∏(deg(v)−1)!
为什么呢?首先我们考虑图的任意一棵根向树,对于再每个节点我们将以 u 为起点的所有不在根向树上的
deg
u
−
1
\deg_u−1
degu−1 条出边(当然如果 u 为根节点就有
deg
u
\deg_u
degu 条不在根向树上的出边)钦定一个顺序,方便起见我们称这个根向树及这个出边的排列顺序为一个“组合”,显然证明原命题我们只需证明一下两个部分:
- 每个组合唯一对应一条欧拉回路
- 每条欧拉回路唯一对应一个组合
树分治
边分治就不讲了(不知它有什么用),有兴趣自己去了解一下。
- 点分治(多路径计数问题大杀器,或是有关两点距离关系的计数问题)
- 思路:每次找到树重心 x,然后**“处理”**经过 x 的路径;再去掉 x ,对子树分治下去。
- **“处理”**是将 两条一端在子树、一端在x 的路径 合并为 “经过 x 的路径”。
- 整个**“处理”**过程的传统思路有两种:
- 1.按顺序处理每棵子树 — 计算 当前子树 与 已处理子树 的贡献;再把 当前子树信息 与 之前的信息 合并。
- 2.去重 — 先把 所有 x 到子树的路径 “无脑合并”(不论路径是否有重边);然后对每个子树,减去在同一子树内“无脑合并”的贡献,即去重。
- 点分树 — 将 x 与每个分治子树的重心 两边,构成一棵树
T
T
T。
- 有什么用?
- 可以发现
T
T
T 是与上述点分治过程息息相关的结构,故 我们可以用
T
T
T 来分析 点分治的复杂度
或是将它的分治过程与整体联系起来(怪怪的) - 经过简单分析,可以发现一些性质
- T T T 的深度不超过 log
- T T T 的子树和为 O ( n log n ) O(n\log n) O(nlogn),可以说明点分治的复杂度。从而,若每层分治需要排序之类的带log操作,复杂度为 O ( n log n ) O(n\log n) O(nlogn)。
- 它最重要的作用还是在于“与分治过程的联系”:
- 发现对于每个点 x ,分治时经过它的路径,会被在它点分树上每个祖先代表的分治层计算。
- 那么如果不是处理全局路径,而是对以 x 为端点的路径进行计算,就可以在点分树祖先处查询(祖先个数是 O ( log ) O(\log) O(log)的)。
- 它还有特殊优势 — 解决带修问题 (动态树分治):
- 思路是,记录下每层分治的信息,对每次修改,维护分治信息的变化 并 考虑它对每层合并的贡献的影响。
- 一般需要 可删堆 或 权值线段树 维护。
树同构相关
-
有 A H U AHU AHU算法 与 树哈希 两种判定方式。
-
A H U AHU AHU算法 — 正确性严格保证。
- 用于有根树,而无根树判定可以通过 定重心为根 转化为有根树同构判定。
- 思路是对树的括号序进行调整再比较。比如,用最小字典序括号序比较。但我们无法承担字符串的存储与比较的代价,所以我们需要 用数“代表”括号序。
-
树哈希 — 方便快捷,便于处理多树同构判定,做有根树判定。
f n o w = s i z n o w × ∑ f s o n ( n o w , i ) × s e e d i − 1 f n o w = ⨁ f s o n ( n o w , i ) × s e e d + s i z s o n ( n o w , i ) f n o w = 1 + ∑ f s o n ( n o w , i ) × p r i m e ( s i z s o n ( n o w , i ) ) \large f_{now}=siz_{now}\times\sum f_{son(now,i)}\times seed^{i-1}\\ \large f_{now}=\bigoplus f_{son(now,i)}\times seed+siz_{son(now,i)}\\ \large f_{now}=1+\sum f_{son(now,i)}\times prime(siz_{son(now,i)}) fnow=siznow×∑fson(now,i)×seedi−1fnow=⨁fson(now,i)×seed+sizson(now,i)fnow=1+∑fson(now,i)×prime(sizson(now,i))
- 第一种方法需排序;第二种容易因同构子树出现次数同奇偶出错;第三种应该挺强的。