网络流学习总结

网络流总结

算法

网络流

设 定义在二元组 上的实数函数且满足

  1. 容量限制:对于每条边,流经该边的流量不得超过该边的容量,即\(f(u,v) \le c(u,v)\)
  2. 斜对称性:每条边的流量与其相反边的流量之和为 0,即 \(f(u,v) = -f(v,u)\)
  3. 流守恒性:从源点流出的流量等于汇点流入的流量

最大流

我们有一张图,要求从源点流向汇点的最大流量(可以有很多条路到达汇点),就是我们的最大流问题。

最小费用最大流

最小费用最大流问题是这样的:每条边都有一个费用,代表单位流量流过这条边的开销。我们要在求出最大流的同时,要求花费的费用最小。

最小割

割其实就是删边的意思,当然最小割就是割掉 \(X\) 条边来让 \(S\)\(T\) 不互通。我们要求 \(X\)条边加起来的流量综合最小。这就是最小割问题。

实现

Dinic 算法 的过程是这样的:每次增广前,我们先用 BFS 来将图分层。设源点的层数为 ,那么一个点的层数便是它离源点的最近距离。

通过分层,我们可以干两件事情:

  1. 如果不存在到汇点的增广路(即汇点的层数不存在),我们即可停止增广。
  2. 确保我们找到的增广路是最短的。(原因见下文)

接下来是 DFS 找增广路的过程。

我们每次找增广路的时候,都只找比当前点层数多 的点进行增广(这样就可以确保我们找到的增广路是最短的)。

Dinic 算法有两个优化:

  1. 多路增广 :每次找到一条增广路的时候,如果残余流量没有用完怎么办呢?我们可以利用残余部分流量,再找出一条增广路。这样就可以在一次 DFS 中找出多条增广路,大大提高了算法的效率。
  2. 当前弧优化 :如果一条边已经被增广过,那么它就没有可能被增广第二次。那么,我们下一次进行增广的时候,就可以不必再走那些已经被增广过的边。

最小费用最大流

网络流图中,花费最小的最大流被称为 最小费用最大流 ,这也是接下来我们要研究的对象。

类似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)\) 。同时必须满足除了源点和汇点之外的其余点流量平衡。

最大权闭合子图

闭合子图:

  1. 它是一种子图
  2. 它还是有向图的子图
  3. 它还可以一路走到底
  4. 对于每个点,从它出发,能够走到的所有点都属于闭合子图中

最大权闭合子图就是原图中点权和最大的闭合子图。

实现

最大权闭合子图问题可以使用最小割解决

连边方式
  • 对于所有原图中的边$ (u, v)$ ,连边 \(u \rightarrow v\),容量为 \(\inf\)

  • 对于每个原图中的点 \(u\) ,设 \(u\) 的权值为 \(val[u]\)

    1. \(val[u] > 0\)(正权点),连边 \(S \rightarrow u\) ,容量为 \(val[u]\)
    2. 若 $val[u] < 0 $(负权点),连边 \(u \rightarrow T\) ,容量为 \(-val[u]\)

至于 \(val[u] = 0\)(零权点)的情况,向 \(S\) 还是 \(T\)连边对答案并没有影响。

直接跑最小割,最大权 = 正点权和 - 最小割,而最大权闭合子图的节点就是与 \(S\) 联通的部分。

技巧

拆点

对于一个有点权的点来说,拆点就是把一个点拆开为多个,这样可以方便把点权变成边权,满足题目的一些要求。

缩点

对于一些题来说,如果直接加点建边很有可能因为边和点过多而挂掉,此时就需要按照题意来进行建边上的优化。

posted @ 2020-04-12 20:34  ztz_cpp  阅读(128)  评论(0编辑  收藏  举报