网络流学习笔记

题单+1

code 合集

网络流

  • 一个有向图,每条边描述一个有向的限制条件,如果我们把它类比为水流的话,每条边就维护一个最大的水流量(容量)。

  • 一般有一个源点(可以流出无限多的水)和一个汇点(所有流进图中的水流都会流入的点)

最大流

  • 对于如上这样一个图,求最大能从源点到汇点流多少水。

EdmondKard 算法

  • 每次找出一条从源点到汇点的径流,然后把途经的边容量都减去当前流量。
    建立反向边,每条途经的边的反向边都加上当前流量。
    重复以上操作,直到不存在任何一个新的流从源点到汇点。

tips:为了节省空间,方便后续查找,一般原边和反向边一起建,\(tot\)\(2\) 开始,这样就可以通过异或运算得到某条边的反向边的编号。

Dinic 算法

  • \(\mathtt{EK}\) 基础上的优化。

  • 将原图进行 \(\mathtt{bfs}\) 分层,然后限制每个流经过的边的端点必须是相邻层中的点,这样就可以同时搜索多个从源点到汇点的流。
    通过 \(\mathtt{DFS}\) 实现具体搜索,因此可以在回溯时修改边的容量(包括反向边)。

tips:如果在搜索中发现向下的某个点能流的流量是 \(0\),可以直接通过修改 \(dep_i\) 的值将其修改为不可访问。

当前弧优化:记录一个 \(now_i\),表示走到 \(i\) 点后再深入应该从哪条边开始。最初 \(now_i=head_i\)
这样可以避免一些无用的递归。(比如一些已经不能再产生流量的边)

tips

  • 一些小技巧。

  • 拆点:当题目中有一些用朴素网络流难以处理的限制条件时,我们可以考虑拆点。比如限制某一个点代表的信息只能使用 \(x\) 次这种条件。
    一般拆法是将这个点拆为一个入点 \(in_i\) 和一个出点 \(out_i\),通过 \(in_i\)\(out_i\) 的边的容量来限制这个条件。(如 P2766 最长不下降子序列问题
    有时需要考虑时间,按时间分层建图,可以将每个点对应时间拆成很多个点。(如 P2754 [CTSC1999]家园 / 星际转移问题

  • 连边方式:比如一道很经典的问题,有 \(F\) 种食品,\(D\) 种饮品,\(n\) 个人各有喜欢的一些食品和饮品,每种食品或饮品都只能被食用一次,求最多能让多少个人满足。
    解决方案为从源点向食品连一条容量为 \(1\) 的边,每种食品向喜欢它的人连一条容量为 \(1\) 的边,每个人拆成入点和出点,中间边的容量也是 \(1\),出点再向它喜欢的饮品连一条容量为 \(1\) 的边,饮品再向汇点连容量为 \(1\) 的边。(当然把食品和饮品的相对位置换一下也可以)

posted @ 2023-03-15 17:15  Star_LIcsAy  阅读(24)  评论(0)    收藏  举报