网络流总结
算法
网络流
设 定义在二元组 上的实数函数且满足
- 容量限制:对于每条边,流经该边的流量不得超过该边的容量,即(f(u,v) le c(u,v))
- 斜对称性:每条边的流量与其相反边的流量之和为 0,即 (f(u,v) = -f(v,u))
- 流守恒性:从源点流出的流量等于汇点流入的流量
最大流
我们有一张图,要求从源点流向汇点的最大流量(可以有很多条路到达汇点),就是我们的最大流问题。
最小费用最大流
最小费用最大流问题是这样的:每条边都有一个费用,代表单位流量流过这条边的开销。我们要在求出最大流的同时,要求花费的费用最小。
最小割
割其实就是删边的意思,当然最小割就是割掉 (X) 条边来让 (S) 跟 (T) 不互通。我们要求 (X)条边加起来的流量综合最小。这就是最小割问题。
实现
Dinic 算法 的过程是这样的:每次增广前,我们先用 BFS 来将图分层。设源点的层数为 ,那么一个点的层数便是它离源点的最近距离。
通过分层,我们可以干两件事情:
- 如果不存在到汇点的增广路(即汇点的层数不存在),我们即可停止增广。
- 确保我们找到的增广路是最短的。(原因见下文)
接下来是 DFS 找增广路的过程。
我们每次找增广路的时候,都只找比当前点层数多 的点进行增广(这样就可以确保我们找到的增广路是最短的)。
Dinic 算法有两个优化:
- 多路增广 :每次找到一条增广路的时候,如果残余流量没有用完怎么办呢?我们可以利用残余部分流量,再找出一条增广路。这样就可以在一次 DFS 中找出多条增广路,大大提高了算法的效率。
- 当前弧优化 :如果一条边已经被增广过,那么它就没有可能被增广第二次。那么,我们下一次进行增广的时候,就可以不必再走那些已经被增广过的边。
最小费用最大流
网络流图中,花费最小的最大流被称为 最小费用最大流 ,这也是接下来我们要研究的对象。
类似Dinic算法
我们可以在 Dinic 算法的基础上进行改进,把 BFS 求分层图改为用 SPFA(由于有负权边,所以不能直接用 Dijkstra)来求一条单位费用之和最小的路径,也就是把 (w(u,v)) 当做边权然后在残量网络上求最短路,当然在 DFS 中也要略作修改。这样就可以求得网络流图的 最小费用最大流 了。
对于一条边 ((u,v,w,c))(其中 (w) 和 (c) 分别为容量和费用),我们建立正向边 (u,v,w,c)和反向边 ((v,u,0,-c))(其中 (-c) 是使得从反向边经过时退回原来的费用)。
上下界网络流
上下界网络流本质是给流量网络的每一条边设置了流量上界 (c(u,v)) 和流量下界 (b(u,v)) 。也就是说,一种可行的流必须满足 (b(u,v) le f(u,v) le c(u,v)) 。同时必须满足除了源点和汇点之外的其余点流量平衡。
最大权闭合子图
闭合子图:
- 它是一种子图
- 它还是有向图的子图
- 它还可以一路走到底
- 对于每个点,从它出发,能够走到的所有点都属于闭合子图中
最大权闭合子图就是原图中点权和最大的闭合子图。
实现
最大权闭合子图问题可以使用最小割解决
连边方式
-
对于所有原图中的边$ (u, v)$ ,连边 (u ightarrow v),容量为 (inf) 。
-
对于每个原图中的点 (u) ,设 (u) 的权值为 (val[u]) :
- 若 (val[u] > 0)(正权点),连边 (S ightarrow u) ,容量为 (val[u])。
- 若 $val[u] < 0 $(负权点),连边 (u ightarrow T) ,容量为 (-val[u])。
至于 (val[u] = 0)(零权点)的情况,向 (S) 还是 (T)连边对答案并没有影响。
直接跑最小割,最大权 = 正点权和 - 最小割,而最大权闭合子图的节点就是与 (S) 联通的部分。
技巧
拆点
对于一个有点权的点来说,拆点就是把一个点拆开为多个,这样可以方便把点权变成边权,满足题目的一些要求。
缩点
对于一些题来说,如果直接加点建边很有可能因为边和点过多而挂掉,此时就需要按照题意来进行建边上的优化。