网络流学习笔记
网络流
感性的定义: 一张DAG,有一个源点s,一个汇点t,其它每条边有一个容量c
从点u到点v的流量:不能让经过的点的流量超出该点的容量
增广路:还能继续流流量的路,也就是有一条路径,路径上的容量都不小于0\
最大流
定义:s到t的最大流量
求最大流算法的核心思路:不停地找增广路,流量加上该增广路上的最小容量,再更新增广路上的容量(路径上每个点都减去路径流量),直到没有增广路。
但但但是,上面的思路还有一个问题,就是该方法不能保证答案正确性,可能走了一条增广路后导致其它路径走不了,有可能不优。于是每条边e要加一条反边e',使得e和e'的容量之和为该边最开始的容量c。每次走边e时,流了x的流量,那么
接下来介绍几种求最大流的算法
- EK算法 复杂度 O(
)
思路:每次bfs找增广路来更新 - dinic算法 复杂度O(
)
思路:先bfs给图分层(标记深度),然后不停地dfs找增广路,但每次只走的dep[v] = dep[u] + 1的边,在该定义下的dfs找不到增广路后再重新bfs给图分层,直到图不连通(没有增广路了)。
优化:dfs走过的点不再走(当前弧优化),不走到汇点t没有流量的点(将dep[该点]赋值成0) - hlpp 复杂度 O(
)
思路:我不会
补充:
- 最大流算法复杂度很玄学,有时会跑地异常的快。
- 对于无向图(在最小割的题目中常见),反边的流量与正边一样。dfs时还是正常地给反边传流量。
【神秘】循环流(相当于无源汇最大流,未知解法)
在循环流问题中,给定一个流网络,其中每条边都有一个容量限制,我们需要找到一个流,使得:
- 每个节点的流入流量等于流出流量。
- 流量尽可能大。
求解方法:未知(求大佬指导)
最小割
定义:割掉一些边,使得s到t不连通,最小割就是割掉的这些边的容量c之和最小的割法。也可以理解为把原图中的点分为两个集合S和T,把S与T相连中的所有边删掉的代价,并且S中包含源点,T中包含汇点。
定理:最小割和最大流的值相等
感性证明:把最大流增广路中容量最小的点割一刀就是最小割(大概吧)
求最小割可以就用最大流的算法,反正值一样
构造:在跑完最大流的残量网络上,把所有s能到的点放进S,剩下的放进T。
【补充】最小割性质
设 λ(a, b) 表示点 a 与 b 在原图上的最小割,则
性质 1:∀a, b, c,λ(a, b) ≥ min(λ(a, c), λ(c, b))
点击查看证明
反证法
假设λ(a, b) < min(λ(a, c), λ(c, b))
那我们可以先用λ(a, b)的费用使a,b不连通。
∵ λ(a, b) < min(λ(a, c), λ(c, b))
∴ 用λ(a, b)的费用不足以使a到c不连通,也不足以使c到b不连通。
所以有一条a->c->b的路径,即a与b连通,假设不成立。
Q.E.D.
性质 2:假设去掉 λ(a, b) 之后得到两部分点集,一部分与 a 相连记作 A,另一部分与 b 相连记作 B,则 ∀p ∈ A, q ∈ B, λ(a, b) ≥ λ(p, q)
点击查看证明
反证法
假设λ(a, b) < λ(p, q)
那我们可以先用λ(a, b)的费用使a,b不连通。
∵ λ(a, b) < λ(p, q)
∴ 用λ(a, b)的费用不足以使p到q不连通。
所以有一条a->p->q->b的路径,即a与b连通,假设不成立。
Q.E.D.
最小割树
用于求任意两点之间的最小割。
构建一颗树,满足:两点之间的路径权值最小值为两点之间的最小割。
构建方法:在当前点集随意选取两个点 u, v,在原图上跑出他们之间的最小割,然后就在树上连一条从 u 到 v, 权值为最小割的边。然后找出 u, v 分属的两个点集(最小割会把原图分成两个点集),对这两个点集递归进行操作。
时间复杂度
正确性证明:
对于两点 x, y,假设 (s, t) 为最小割树上 x 到 y 路径上边权最小的边,根据性质 1有 λ(x, y) ≥ λ(s, t),根据性质 2 有 λ(s, t) ≥ λ(x, y),于是 λ(s, t) = λ(x, y)。
最大权闭合子图
定义:对于每一个点赋一个值,求一个点集,点集内的所有点都必须包含它的所有后继,使这个点集的和最大。
形式化地说:H 是 G = (V,E) 的一个子图,如果 ∀u ∈ H,(u, v) ∈ E,都有 v ∈ H,则称 H 是 G 的一个闭合子图。现要选出一个闭合子图,最大化它的点权之和。
建图如下:(设
- 对于原图 G 中的边 u → v,在网络流图中建边 u → v,容量为 ∞,表示这条边一定不会被割掉。
- 对于正权点 u,连边 s → u,容量为 au
- 对于负权点 v,连边 v → t,容量为 |av|
跑一个最小割,答案为:所有正权之和sum − 最小割。
因为:割掉一条源点上的边代表你不会选择这个点,而割掉连向汇点上的一条边代表你会选择这个点。
如果图不联通,那么选的点集一定合法,因为如果联通,说明你选择了正点,而正点有负点后继没有进行选择。
费用流
定义:现在每条边不仅有容量c,还有花费w。要求走最大流的同时保证路径上的总花费(
EK做法:将反边费用设为-w,找增广路时用spfa(这里用spfa是因为有负权)。以EK为例,把bfs改成spfa。
dinic做法:把用bfs给图分层,改用spfa,具体来说在后面dfs时,只走dis[u] + w = dis[v]的边。
有上下界的可行流/最大流
一张 n个点 m条边网络流,其中每条边有一个流量限制[Li,Ri]表示这条边流量的范围。
先给每一条有下界的边u->v,“预支”它下界的流量,并且记录一下u和v预支的流量。也就是w[u] -= flow, w[v] += flow。
现在每个点都有一些积蓄/欠缺的流量,用数组w记录。但是现在流量就不守恒了,于是我们凭空构造一个虚拟源点s和汇点t。
无汇源上下界可行流
因为没有源汇,所以这张网络流需要满足流入每个点的流量总量=流出的流量总量。
对于 w[i] > 0 的点,使用s向它连一条流量为w[i]的边,如果w[i] < 0,则用t向他连一条流量为 -w[i] 的边,w[i] = 0的点直接跳过。
统计一下w[i] > 0的w值,记为sum,如果是有可行流,那么从s到t跑出来的最大流 等于sum,说明原图支持把预支的流量流满。
有汇源上下界可行流
记题目给定的汇源点为ss和tt。
ss和tt的流量可以不守恒,这样很难搞,于是tt向ss连一条容量无限的边,这样流量就守恒了。
所以现在又可以从虚拟汇源点s到t跑最大流了。值得注意的是,这条边流过的流量大小就是可行流。(本蒟蒻也不知道为什么)
有汇源上下界最大流
跑完可行流后,再用残余网络,从原图汇源点ss到tt跑最大流。
按理说,答案应该是跑出来的可行流再加上最大流加上可行流,但是因为“tt到ss这条边流过的流量大小就是可行流”,所以相应的,反边ss到tt有一条流量为可行流的边,所以后面跑最大流是会统计可行流的流量。
有源汇上下界最小流(摘自:某篇题解)
我们看到有源点和汇点的上下界最小流,即在可行流的基础上要求流量最小。
我们先跑一遍可行流,设可行流为flow1
则最小流为可行流−还能向下浮动的流量flow2
其实我们可以发现还能向下浮动的流量就是从原图汇点到原图源点的最大流(感性理解)。
因此步骤为:
- 跑出一个有源汇上下界可行流,如果满流则设其答案为flow1,否则不存在答案。
- 删去从原图汇点到原图源点的边。
- 跑从原图汇点到原图源点的最大流,设答案为flow2,则总答案ans=flow1−flow2。
柯尼希定理
定义:二分图最小点覆盖的点数等于最大匹配数。
证明:对于一个二分图,其最大匹配已经确定,从右边没有匹配的点出发走交替路,将所有从右边没有匹配的点开始的交替路上的所有的点标注起来。可以证明左边所有被标注的点都是被匹配的点,右边所有没有被标注的点也都是被匹配的点,这些点构成最小覆盖点集。
示例(来自百度):
我们称下图中的下部分点集合为L,上部分的点集合为R。从左至右给下部分的每个点标号为1,…,7;并给上部分的点标号为8,…,14。令U为L中未匹配的点的集合,U={1}。从U出发的增广路径为1-10-3-13-7, 1-10-3-11-5-13-7, 1-11-5-13-7, 1-11-5-10-3-13-7及它们的子路径,那么构造性证明中的集合Z为{1,3,5,7,10,11,13},可以得到L\Z={2,4,6},所以最小点覆盖
应用:该定理为在给定最大匹配的情况下寻找最小点覆盖提供了算法依据,二分图最大匹配算法可用于解决相关问题。
推论:二分图的最大独立集的大小=点数n−最大匹配数。最大独立集的构造方法就是取最小点覆盖集的补集。
最大独立集:图中最大的顶点集合,其中任意两个顶点之间没有边相连。
在任何图中,最大独立集和最小点覆盖是互补的。即,如果一个顶点集合是最大独立集,那么它的补集(所有不在最大独立集中的顶点)就是最小点覆盖。
因此,最大独立集的大小加上最小点覆盖的大小等于图的总点数n。
进一步还可以解决DAG的最小路径覆盖问题:
- DAG的最小不相交路径覆盖(点只能走一次,边也只能走一次)
将每个点u拆成uL和uR,作为二分图的左右部点。如果DAG有边u→v,则在二分图上加边uL→vR。
原本每个点作为一条路径,覆盖整个DAG,每产生一个匹配,就相当于把两条路径拼了起来,路径数量−1,于是DAG的最小不相交路径覆盖的路径数=原图的点数−二分图的最大匹配数。
模板题 - DAG的最小可相交路径覆盖(点可以走无限次,边只能走一次)
解法1:
该问题要处理每个点可以反复经过的情况,但这可能不太好处理,考虑如何让每个点只经过一次。
假设有一条a -> b -> c的边,和一条d -> b -> e的边,如果我们现在想要同时选取这两条边,可以让d连向e,这样就可以保证让每个点只经过一次。
更形式化地说,我们求出每个点u可以到达的点的点集S,然后让u向S中每个点连一条边,再用DAG的最小不相交路径覆盖来做。
Floyd求出原图的传递闭包即可求出每个点u可以到达的点的点集S。Floyd传递闭包
解法2:(hkx大佬用上下界费用流直接秒了)
把每个点u拆分成左部点lu和右部点ru,加一个虚拟源点S和虚拟汇点T。
因为每个点都至少被覆盖一次,所以连一条lu->ru的边,流量下界为1,上界正无穷,费用为0。
对于原图中的边u->v,连一条ru->lv的边,无上下界(下界为0,上界正无穷),费用为0。
源点S向每一个左部点连边,无上下界(或把上界设为1),费用为1。
汇点T向每一个右部点连边,无上下界,费用为0。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析