Commit 539d6d81 authored by sshwy's avatar sshwy
Browse files

bridge and flow

parent 6c34fa31
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -46,8 +46,6 @@ low[u] = min(low[u], num[v]);

 [洛谷 P3388【模板】割点(割顶)](https://www.luogu.org/problemnew/show/P3388) 

### Code

??? "例题代码"
    ```cpp
    /*
+135 −135
Original line number Diff line number Diff line
@@ -332,11 +332,13 @@ struct ISAP {

## Push-Relabel 预流推进算法

该方法在求解过程中忽略流守恒性,并每次对一个结点更新信息,以求解最大流
该方法在求解过程中忽略流守恒性,并每次对一个结点更新信息,以求解最大流

有 HLPP 的主流算法
### 通用的预流推进算法

推送 - 重贴标签算法通过对单个结点的更新操作,直到没有结点需要更新来求解最大流
首先我们介绍预流推进算法的主要思想,以及一个可行的暴力实现算法。

预流推进算法通过对单个结点的更新操作,直到没有结点需要更新来求解最大流。

算法过程维护的流函数不一定保持流守恒性,对于一个结点,我们允许进入结点的流超过流出结点的流,超过的部分被称为结点 $u(u\in V-\{s,t\})$ 的 **超额流**  $e(u)$ :

@@ -344,24 +346,24 @@ $$
e(u)=\sum_{(x,u)\in E}f(x,u)-\sum_{(u,y)\in E}f(u,y)
$$

若 $e(u)>0$ ,称结点 $u$  **溢出** .
若 $e(u)>0$ ,称结点 $u$  **溢出** 

推送 - 重贴标签算法维护每个结点的高度 $h(u)$ ,并且规定溢出的结点 $u$ 如果要推送超额流,只能向高度小于 $u$ 的结点推送;如果 $u$ 没有相邻的高度小于 $u$ 的结点,就修改 $u$ 的高度(重贴标签)。
预流推进算法维护每个结点的高度 $h(u)$ ,并且规定溢出的结点 $u$ 如果要推送超额流,只能向高度小于 $u$ 的结点推送;如果 $u$ 没有相邻的高度小于 $u$ 的结点,就修改 $u$ 的高度(重贴标签)。

#### 高度函数

准确地说,推送 - 重贴标签维护以下的一个映射 $h:V\to \mathbf{N}$ :
准确地说,预流推进维护以下的一个映射 $h:V\to \mathbf{N}$ :

-    $h(s)=|V|,h(t)=0$ 
-    $\forall (u,v)\in E_f,h(u)\leq h(v)+1$ 

称 $h$ 是残存网络 $G_f=(V_f,E_f)$ 的高度函数。
称 $h$ 是残存网络 $G_f=(V_f,E_f)$ 的高度函数。

引理 1:设 $G_f$ 上的高度函数为 $h$ ,对于任意两个结点 $u,v\in V$ ,如果 $h(u)>h(v)+1$ ,则 $(u,v)$ 不是 $G_f$ 中的边。

算法只会在 $h(u)=h(v)+1$ 的边执行推送。

#### 推送 -Push
#### 推送Push

适用条件:结点 $u$ 溢出,且存在结点 $v((u,v)\in E_f,c(u,v)-f(u,v)>0,h(u)=h(v)+1)$ ,则 push 操作适用于 $(u,v)$ 。

@@ -369,7 +371,7 @@ $$

如果 $(u,v)$ 在推送完之后满流,将其从残存网络中删除。

#### 重贴标签 -Relabel
#### 重贴标签Relabel

适用条件:如果结点 $u$ 溢出,且 $\forall (u,v)\in E_f,h(u)\leq h(v)$ ,则 relabel 操作适用于 $u$ 。

@@ -394,11 +396,9 @@ $$

上述将 $(s,v)\in E$ 充满流,并将 $h(s)$ 抬高,使得 $(s,v)\notin E_f$ ,因为 $h(s)>h(v)$ ,而且 $(s,v)$ 毕竟满流,没必要留在残存网络中;上述还将 $e(s)$ 初始化为 $\sum_{(s,v)\in E}f(s,v)$ 的相反数。

#### 通用执行框架

无需按照特定顺序,执行以下过程:
#### 通用算法

-   只要存在结点 $u$ 满足 push 或 relabel 的条件,就执行对应的操作。
我们每次扫描整个图,只要存在结点 $u$ 满足 push 或 relabel 操作的条件,就执行对应的操作。

如图,每个结点中间表示编号,左下表示高度值 $h(u)$ ,右下表示超额流 $e(u)$ ,结点颜色的深度也表示结点的高度;边权表示 $c(u,v)-f(u,v)$ ,绿色的边表示满足 $h(u)=h(v)+1$ 的边 $(u,v)$ (即残存网络的边 $E_f$ ):

@@ -414,7 +414,7 @@ $$

可以发现,最后的超额流一部分回到了 $s$ ,且除了源点汇点,其他结点都没有溢出;这时的流函数 $f$ 满足流守恒性,为最大流,即 $e(t)$ 。

#### 核心代码
???+ "核心代码"
    
    ```cpp
    const int N = 1e4 + 4, M = 1e5 + 5, INF = 0x3f3f3f3f;
@@ -443,13 +443,13 @@ void relabel(int u) {

### HLPP 算法

最高标号预流推进算法(High Level Preflow Push)是基于推送 - 重贴标签算法的优先队列实现,该算法优先推送高度高的溢出的结点,算法算法复杂度 $O(n^2\sqrt m)$ 。
最高标号预流推进算法(High Level Preflow Push)是基于预流推进算法的优先队列实现,该算法优先推送高度高的溢出的结点,算法算法复杂度 $O(n^2\sqrt m)$ 。

具体地说,HLPP 维护以下过程
具体地说,HLPP 算法过程如下

1.  初始化(基于推送 - 重贴标签算法);
1.  初始化(基于预流推进算法);
2.  选择溢出结点(除 $s,t$ )中高度最高的结点 $u$ ,并对它所有可以推送的边进行推送;
3.  如果 $u$ 仍溢出,对它重贴标签,回到 2;
3.  如果 $u$ 仍溢出,对它重贴标签,回到步骤 2;
4.  如果没有溢出的结点,算法结束。

#### BFS 优化
@@ -464,7 +464,7 @@ HLPP 的上界为 $O(n^2\sqrt m)$ ,但在使用时卡得比较紧;我们可

HLPP 推送的条件是 $h(u)=h(v)+1$ ,而如果在算法的某一时刻, $h(u)=t$ 的结点个数为 $0$ ,那么对于 $h(u)>t$ 的结点就永远无法推送超额流到 $t$ ,因此只能送回 $s$ ,那么我们就在这时直接让他们的高度变成 $n+1$ ,以尽快推送回 $s$ ,减少重贴标签的操作。

#### LuoguP4722【模板】最大流 加强版/预流推进
???+ "LuoguP4722【模板】最大流 加强版/预流推进"
    
    ```cpp
    #include <cstdio>