Loading docs/graph/flow/max-flow.md +34 −33 Original line number Diff line number Diff line ## 网络 网络是指一个有向图 $G=(V,E)$ 网络是指一个有向图 $G=(V,E)$。 每条边 $(u,v)\in E$ 都有一个权值 $c(u,v)$,称之为容量(Capacity),当 $(u,v)\notin E$ 时有 $c(u,v)=0$. 每条边 $(u,v)\in E$ 都有一个权值 $c(u,v)$,称之为容量(Capacity),当 $(u,v)\notin E$ 时有 $c(u,v)=0$。 其中有两个特殊的点:源点 $s\in V$ 和汇点 $t\in V,(s\neq t)$. 其中有两个特殊的点:源点 $s\in V$ 和汇点 $t\in V,(s\neq t)$。 ## 流 Loading @@ -14,13 +14,14 @@ 2. **斜对称性**:$f(u,v)=-f(v,u)$ 3. **流守恒性**:$\forall x\in V-\{s,t\},\sum_{(u,x)\in E}f(u,x)=\sum_{(x,v)\in E}f(x,v)$ 那么 $f$ 称为网络 $G$ 的流函数 那么 $f$ 称为网络 $G$ 的流函数。 对于 $(u,v)\in E$,$f(u,v)$ 称为边的**流量**,$c(u,v)-f(u,v)$ 称为边的**剩余容量** 对于 $(u,v)\in E$,$f(u,v)$ 称为边的**流量**,$c(u,v)-f(u,v)$ 称为边的**剩余容量**。 整个网络的流量为 $\sum_{(s,v)\in E}f(s,v)$,即**从源点发出的所有流量之和** 整个网络的流量为 $\sum_{(s,v)\in E}f(s,v)$,即**从源点发出的所有流量之和**。 *注*:流函数的完整定义为 $$ f(u,v)=\left\{\begin{split} &f(u,v)&,(u,v)\in E\\ Loading @@ -37,9 +38,7 @@ $$ ## FF增广路算法 该方法通过寻找增广路来更新最大流 有 EK,dinic,SAP,ISAP 主流算法 该方法通过寻找增广路来更新最大流,有 EK,dinic,SAP,ISAP 主流算法。 求解最大流之前,我们先认识以下增广路的概念。 Loading @@ -55,9 +54,9 @@ $$ 所以我们这张图的最大流就应该是 $20+30=50$ 。 求最大流是很简单的,接下来讲解求最大流的 $3$ 种方法。 求最大流是很简单的,接下来讲解求最大流的 3 种方法。 ### Edmond-Karp 动能算法( $EK$ 算法) ### Edmond-Karp 动能算法(EK 算法) 这个算法很简单,就是 BFS **找增广路** ,然后对其进行 **增广** 。你可能会问,怎么找?怎么增广? Loading Loading @@ -242,24 +241,26 @@ int main() { 该方法在求解过程中忽略流守恒性,并每次对一个结点更新信息,以求解最大流 有 $HLPP$ 的主流算法 有 HLPP 的主流算法 推送 - 重贴标签算法通过对单个结点的更新操作,直到没有结点需要更新来求解最大流 算法过程维护的流函数不一定保持流守恒性,对于一个结点,我们允许进入结点的流超过流出结点的流,超过的部分被称为结点 $u(u\in V-\{s,t\})$ 的**超额流**$e(u)$: $$ e(u)=\sum_{(x,u)\in E}f(x,u)-\sum_{(u,y)\in E}f(u,y) $$ 若 $e(u)>0$,称结点 $u$**溢出**. 推送 - 重贴标签算法维护每个结点的高度 $h(u)$,并且规定溢出的结点 $u$ 如果要推送超额流,只能向高度小于 $u$ 的结点推送;如果 $u$ 没有相邻的高度小于 $u$ 的结点,就修改 $u$ 的高度(重贴标签). 推送 - 重贴标签算法维护每个结点的高度 $h(u)$,并且规定溢出的结点 $u$ 如果要推送超额流,只能向高度小于 $u$ 的结点推送;如果 $u$ 没有相邻的高度小于 $u$ 的结点,就修改 $u$ 的高度(重贴标签)。 #### 高度函数 准确地说,推送 - 重贴标签维护以下的一个映射 $h:V\to \mathbb{N}$: 准确地说,推送 - 重贴标签维护以下的一个映射 $h:V\to \mathbf{N}$: - $h(s)=|V|,h(t)=0$ - $\forall (u,v)\in E_f,h(u)\leq h(v)+1$. - $\forall (u,v)\in E_f,h(u)\leq h(v)+1$ 则称 $h$ 是残存网络 $G_f=(V_f,E_f)$ 的高度函数。 Loading @@ -269,15 +270,15 @@ $$ #### 推送 -Push 适用条件:结点 $u$ 溢出,且存在结点 $v((u,v)\in V_f,c(u,v)-f(u,v)>0,h(u)=h(v)+1)$,则 push 操作适用于 $(u,v)$. 适用条件:结点 $u$ 溢出,且存在结点 $v((u,v)\in V_f,c(u,v)-f(u,v)>0,h(u)=h(v)+1)$,则 push 操作适用于 $(u,v)$。 于是,我们尽可能将超额流从 $u$ 推送到 $v$,推送过程中我们只关心超额流和 $c(u,v)-f(u,v)$ 的最小值,不关心 $v$ 是否溢出。 如果 $(u,v)$ 在推送完之后满流,将其从残存网络中删除 如果 $(u,v)$ 在推送完之后满流,将其从残存网络中删除。 #### 重贴标签 -Relabel 适用条件:如果结点 $u$ 溢出,且 $\forall (u,v)\in E_f,h(u)\leq h(v)$,则 relabel 操作适用于 $u$. 适用条件:如果结点 $u$ 溢出,且 $\forall (u,v)\in E_f,h(u)\leq h(v)$,则 relabel 操作适用于 $u$。 则将 $h(u)$ 更新为 $min_{(u,v)\in E_f}h(v)+1$ 即可。 Loading Loading @@ -318,7 +319,7 @@ $$  可以发现,最后的超额流一部分回到了 $s$,且除了源点汇点,其他结点都没有溢出;这时的流函数 $f$ 满足流守恒性,为最大流,即 $e(t)$. 可以发现,最后的超额流一部分回到了 $s$,且除了源点汇点,其他结点都没有溢出;这时的流函数 $f$ 满足流守恒性,为最大流,即 $e(t)$。 #### 核心代码 Loading Loading @@ -346,26 +347,26 @@ void relabel(int u){ ### HLPP 算法 最高标号预流推进算法(High Level Preflow Push)是基于推送 - 重贴标签算法的优先队列实现,该算法优先推送高度高的溢出的结点,算法算法复杂度 $O(n^2\sqrt m)$. 最高标号预流推进算法(High Level Preflow Push)是基于推送 - 重贴标签算法的优先队列实现,该算法优先推送高度高的溢出的结点,算法算法复杂度 $O(n^2\sqrt m)$.=。 具体地说,HLPP 维护以下过程: 1. 初始化(基于推送 - 重贴标签算法) 1. 初始化(基于推送 - 重贴标签算法); 2. 选择溢出结点(除 $s,t$)中高度最高的结点 $u$,并对它所有可以推送的边进行推送; 3. 如果 $u$ 仍溢出,对它重贴标签,回到 2. 4. 如果没有溢出的结点,算法结束 3. 如果 $u$ 仍溢出,对它重贴标签,回到 2; 4. 如果没有溢出的结点,算法结束。 #### BFS 优化 HLPP 的上界为 $O(n^2\sqrt m)$,但在使用时卡得比较紧;我们可以在初始化高度的时候进行优化 HLPP 的上界为 $O(n^2\sqrt m)$,但在使用时卡得比较紧;我们可以在初始化高度的时候进行优化: 具体来说,我们初始化 $h(u)$ 为 $u$ 到 $t$ 的最短距离;特别地,$h(s)=n$. 具体来说,我们初始化 $h(u)$ 为 $u$ 到 $t$ 的最短距离;特别地,$h(s)=n$。 在 BFS 的同时我们顺便检查图的联通性,排除无解的情况 在 BFS 的同时我们顺便检查图的联通性,排除无解的情况。 #### GAP 优化 HLPP 推送的条件是 $h(u)=h(v)+1$,而如果在算法的某一时刻,$h(u)=t$ 的结点个数为 0,那么对于 $h(u)>t$ 的结点就永远无法推送超额流到 $t$,因此只能送回 $s$,那么我们就在这时直接让他们的高度变成 $n+1$,以尽快推送回 $s$,减少重贴标签的操作 HLPP 推送的条件是 $h(u)=h(v)+1$,而如果在算法的某一时刻,$h(u)=t$ 的结点个数为 $0$,那么对于 $h(u)>t$ 的结点就永远无法推送超额流到 $t$,因此只能送回 $s$,那么我们就在这时直接让他们的高度变成 $n+1$,以尽快推送回 $s$,减少重贴标签的操作。 #### [LuoguP4722] 【模板】最大流 加强版 / 预流推进 Loading Loading @@ -449,4 +450,4 @@ int main(){  其中 $pic13$ 到 $pic14$ 执行了 $Relabel(4)$,并进行了 GAP 优化 其中 pic13 到 pic14 执行了 Relabel(4),并进行了 GAP 优化 Loading
docs/graph/flow/max-flow.md +34 −33 Original line number Diff line number Diff line ## 网络 网络是指一个有向图 $G=(V,E)$ 网络是指一个有向图 $G=(V,E)$。 每条边 $(u,v)\in E$ 都有一个权值 $c(u,v)$,称之为容量(Capacity),当 $(u,v)\notin E$ 时有 $c(u,v)=0$. 每条边 $(u,v)\in E$ 都有一个权值 $c(u,v)$,称之为容量(Capacity),当 $(u,v)\notin E$ 时有 $c(u,v)=0$。 其中有两个特殊的点:源点 $s\in V$ 和汇点 $t\in V,(s\neq t)$. 其中有两个特殊的点:源点 $s\in V$ 和汇点 $t\in V,(s\neq t)$。 ## 流 Loading @@ -14,13 +14,14 @@ 2. **斜对称性**:$f(u,v)=-f(v,u)$ 3. **流守恒性**:$\forall x\in V-\{s,t\},\sum_{(u,x)\in E}f(u,x)=\sum_{(x,v)\in E}f(x,v)$ 那么 $f$ 称为网络 $G$ 的流函数 那么 $f$ 称为网络 $G$ 的流函数。 对于 $(u,v)\in E$,$f(u,v)$ 称为边的**流量**,$c(u,v)-f(u,v)$ 称为边的**剩余容量** 对于 $(u,v)\in E$,$f(u,v)$ 称为边的**流量**,$c(u,v)-f(u,v)$ 称为边的**剩余容量**。 整个网络的流量为 $\sum_{(s,v)\in E}f(s,v)$,即**从源点发出的所有流量之和** 整个网络的流量为 $\sum_{(s,v)\in E}f(s,v)$,即**从源点发出的所有流量之和**。 *注*:流函数的完整定义为 $$ f(u,v)=\left\{\begin{split} &f(u,v)&,(u,v)\in E\\ Loading @@ -37,9 +38,7 @@ $$ ## FF增广路算法 该方法通过寻找增广路来更新最大流 有 EK,dinic,SAP,ISAP 主流算法 该方法通过寻找增广路来更新最大流,有 EK,dinic,SAP,ISAP 主流算法。 求解最大流之前,我们先认识以下增广路的概念。 Loading @@ -55,9 +54,9 @@ $$ 所以我们这张图的最大流就应该是 $20+30=50$ 。 求最大流是很简单的,接下来讲解求最大流的 $3$ 种方法。 求最大流是很简单的,接下来讲解求最大流的 3 种方法。 ### Edmond-Karp 动能算法( $EK$ 算法) ### Edmond-Karp 动能算法(EK 算法) 这个算法很简单,就是 BFS **找增广路** ,然后对其进行 **增广** 。你可能会问,怎么找?怎么增广? Loading Loading @@ -242,24 +241,26 @@ int main() { 该方法在求解过程中忽略流守恒性,并每次对一个结点更新信息,以求解最大流 有 $HLPP$ 的主流算法 有 HLPP 的主流算法 推送 - 重贴标签算法通过对单个结点的更新操作,直到没有结点需要更新来求解最大流 算法过程维护的流函数不一定保持流守恒性,对于一个结点,我们允许进入结点的流超过流出结点的流,超过的部分被称为结点 $u(u\in V-\{s,t\})$ 的**超额流**$e(u)$: $$ e(u)=\sum_{(x,u)\in E}f(x,u)-\sum_{(u,y)\in E}f(u,y) $$ 若 $e(u)>0$,称结点 $u$**溢出**. 推送 - 重贴标签算法维护每个结点的高度 $h(u)$,并且规定溢出的结点 $u$ 如果要推送超额流,只能向高度小于 $u$ 的结点推送;如果 $u$ 没有相邻的高度小于 $u$ 的结点,就修改 $u$ 的高度(重贴标签). 推送 - 重贴标签算法维护每个结点的高度 $h(u)$,并且规定溢出的结点 $u$ 如果要推送超额流,只能向高度小于 $u$ 的结点推送;如果 $u$ 没有相邻的高度小于 $u$ 的结点,就修改 $u$ 的高度(重贴标签)。 #### 高度函数 准确地说,推送 - 重贴标签维护以下的一个映射 $h:V\to \mathbb{N}$: 准确地说,推送 - 重贴标签维护以下的一个映射 $h:V\to \mathbf{N}$: - $h(s)=|V|,h(t)=0$ - $\forall (u,v)\in E_f,h(u)\leq h(v)+1$. - $\forall (u,v)\in E_f,h(u)\leq h(v)+1$ 则称 $h$ 是残存网络 $G_f=(V_f,E_f)$ 的高度函数。 Loading @@ -269,15 +270,15 @@ $$ #### 推送 -Push 适用条件:结点 $u$ 溢出,且存在结点 $v((u,v)\in V_f,c(u,v)-f(u,v)>0,h(u)=h(v)+1)$,则 push 操作适用于 $(u,v)$. 适用条件:结点 $u$ 溢出,且存在结点 $v((u,v)\in V_f,c(u,v)-f(u,v)>0,h(u)=h(v)+1)$,则 push 操作适用于 $(u,v)$。 于是,我们尽可能将超额流从 $u$ 推送到 $v$,推送过程中我们只关心超额流和 $c(u,v)-f(u,v)$ 的最小值,不关心 $v$ 是否溢出。 如果 $(u,v)$ 在推送完之后满流,将其从残存网络中删除 如果 $(u,v)$ 在推送完之后满流,将其从残存网络中删除。 #### 重贴标签 -Relabel 适用条件:如果结点 $u$ 溢出,且 $\forall (u,v)\in E_f,h(u)\leq h(v)$,则 relabel 操作适用于 $u$. 适用条件:如果结点 $u$ 溢出,且 $\forall (u,v)\in E_f,h(u)\leq h(v)$,则 relabel 操作适用于 $u$。 则将 $h(u)$ 更新为 $min_{(u,v)\in E_f}h(v)+1$ 即可。 Loading Loading @@ -318,7 +319,7 @@ $$  可以发现,最后的超额流一部分回到了 $s$,且除了源点汇点,其他结点都没有溢出;这时的流函数 $f$ 满足流守恒性,为最大流,即 $e(t)$. 可以发现,最后的超额流一部分回到了 $s$,且除了源点汇点,其他结点都没有溢出;这时的流函数 $f$ 满足流守恒性,为最大流,即 $e(t)$。 #### 核心代码 Loading Loading @@ -346,26 +347,26 @@ void relabel(int u){ ### HLPP 算法 最高标号预流推进算法(High Level Preflow Push)是基于推送 - 重贴标签算法的优先队列实现,该算法优先推送高度高的溢出的结点,算法算法复杂度 $O(n^2\sqrt m)$. 最高标号预流推进算法(High Level Preflow Push)是基于推送 - 重贴标签算法的优先队列实现,该算法优先推送高度高的溢出的结点,算法算法复杂度 $O(n^2\sqrt m)$.=。 具体地说,HLPP 维护以下过程: 1. 初始化(基于推送 - 重贴标签算法) 1. 初始化(基于推送 - 重贴标签算法); 2. 选择溢出结点(除 $s,t$)中高度最高的结点 $u$,并对它所有可以推送的边进行推送; 3. 如果 $u$ 仍溢出,对它重贴标签,回到 2. 4. 如果没有溢出的结点,算法结束 3. 如果 $u$ 仍溢出,对它重贴标签,回到 2; 4. 如果没有溢出的结点,算法结束。 #### BFS 优化 HLPP 的上界为 $O(n^2\sqrt m)$,但在使用时卡得比较紧;我们可以在初始化高度的时候进行优化 HLPP 的上界为 $O(n^2\sqrt m)$,但在使用时卡得比较紧;我们可以在初始化高度的时候进行优化: 具体来说,我们初始化 $h(u)$ 为 $u$ 到 $t$ 的最短距离;特别地,$h(s)=n$. 具体来说,我们初始化 $h(u)$ 为 $u$ 到 $t$ 的最短距离;特别地,$h(s)=n$。 在 BFS 的同时我们顺便检查图的联通性,排除无解的情况 在 BFS 的同时我们顺便检查图的联通性,排除无解的情况。 #### GAP 优化 HLPP 推送的条件是 $h(u)=h(v)+1$,而如果在算法的某一时刻,$h(u)=t$ 的结点个数为 0,那么对于 $h(u)>t$ 的结点就永远无法推送超额流到 $t$,因此只能送回 $s$,那么我们就在这时直接让他们的高度变成 $n+1$,以尽快推送回 $s$,减少重贴标签的操作 HLPP 推送的条件是 $h(u)=h(v)+1$,而如果在算法的某一时刻,$h(u)=t$ 的结点个数为 $0$,那么对于 $h(u)>t$ 的结点就永远无法推送超额流到 $t$,因此只能送回 $s$,那么我们就在这时直接让他们的高度变成 $n+1$,以尽快推送回 $s$,减少重贴标签的操作。 #### [LuoguP4722] 【模板】最大流 加强版 / 预流推进 Loading Loading @@ -449,4 +450,4 @@ int main(){  其中 $pic13$ 到 $pic14$ 执行了 $Relabel(4)$,并进行了 GAP 优化 其中 pic13 到 pic14 执行了 Relabel(4),并进行了 GAP 优化