「学习笔记」网络流基础

注:此博客写于 2017.11

前言

今年NOIP2017提高的初赛考到的最小割。这是否意味着网络流进入NOIP考纲?

蒟蒻Cyani发现,周围的同学都会网络流啊。蒟蒻也来学一学姿势。

比较推荐LRJ的蓝书,胡伯涛的论文,关于模版和建模有比较详细的讲解。

听说CF的网络流质量挺高的?

还有BZOJ的网络流。

为了使叙述更加易懂,本文尽可能减少数学符号的使用。

前置技能

最大流

每次找到最短增广路径,最坏增广 \(O(nm)\) 次。所以时间复杂度取决于找最短增广路径的时间复杂度。

EK算法。 直接暴力 \(BFS\) ,复杂度 \(O(nm^2)\)

Dinic算法。 按照起点到 \(u\) 的距离分层,沿着分层网络上的边增广,直到 \(s\) 无法到达 \(t\) 。重复以上步骤。最多重复 \(O(n)\) 次,每次复杂度 \(O(nm)\) 。总的复杂度 \(O(n^2m)\)

ISAP算法。 EK算法的改进版,做法类似于Dinic,维护每个点到终点的最大距离(没有暴力重新计算,而是增广过程中更新)。需要增加当前弧优化,GAP优化。复杂度 \(O(n^2m)\) ,常数比Dinic小。

推荐ISAP,详见这篇博文

网络流算法Dinic跑二分图时,复杂度为 \(O(\sqrt n m)\) 。经过实践,ISAP跑二分图的复杂度也差不多,似乎常数略大?

最大流最小割定理

一个图的割定义为, \(s,t\) 分别所属两个点集 \(S,T=V-S\) ,代价定义为 \(S\)\(T\) 所有边的代价总和。

最大流=最小割。

关键的证明步骤:是最大流->不存在增广路径->可以构造一个割使之等于流->是最大流。证明等价性。

关键在于 构造 这个割。

\(S\)\(s\) 能够达到的点集,那么对于任意 \(u \in S, v \in T\) 都有 \(f(u,v)=c(u,v)\) ,否则 \((u,v)\) 就属于残量了,与前提矛盾。不难发现这个割的容量总和等于流量。

注意:最小割之间的边一定是满流的边,反过来不一定成立。

最小费用最大流

注意到一个网络的最大流并不是唯一的。有一类题会在边上附加单位流量费用。最小费用最大流用于解决当流量最大时,最小的费用总和。

EK-SPFA算法。 在EK算法BFS寻找最短路的基础上,改成SPFA寻找最短路。复杂度 \(O(nmF)\) ,其中 \(F\) 表示最大流量,事实上远小于这个上界。

zkw费用流。 先挖坑。。

其实我的费用流模版比ISAP短诶。。

常见模型

Simple

这些小技巧的正确性就挺显然的吧。。

多源多汇。 增加超级源 \(s'\) ,超级汇 \(t'\) ,连上流量无穷的边。

节点容量。 将一个点 \(u\) 拆成两个点 \(u1,u2\)\(u1\rightarrow u2\) 连上节点容量的边,入边连上\(u1\),出边连上\(u2\)。同样适用于节点费用。

动态加边。 不能更改原来边的容量,费用。注意无后效性!

费用流如何应用? 首先需要确保达到最大流,必要时限流。否则费用流就没有意义了。

费用不是线性关系。 拆边。比如流量 \(x\) 的费用为 \(x^2\) ,此时可以分段。具体来说,连上流量 \(1\) ,费用 \(cost(1)-cost(0)\) ,流量 \(1\) ,费用 \(cost(2)-cost(1)\) 。。这个例子对应的流量就是 \(1,3,5,...\)

费用流限流。 在汇点之后再加一条边到超级汇,限制流量。

最大权闭合子图

对于一个有向图 \(G\) 对于其的一个子集 \(N\) 满足:闭合子图中的所有节点指向的,都是闭合子图的节点。赋予每个点一个权值\(wi\),要求最大化闭合子图的权值。

构图方法。 对于原图中的边,替换为流量无穷的边;对于权值为正的节点,源\(S\)向这个节点连接容量为\(wi\)的边;对于权值为负的节点,这个节点连向汇点容量为 \(-wi\) 的边。

感性证明。 注意到一个性质:新的图的最小割一定不包含容量无限的边(称这种割为简单个)。于是满足闭合子图的定义,每个简单割的 \(S\) 集一一对应一个闭合子图。

设所有正数的权之和为 \(sum\) ,最小割为 \(w\) 。发现闭合子图的权就是 \(sum-w\) ,于是我们需要最小化 \(w\) ,才能最大化闭合子图的权。

最大密度子图

对于一个无向图,定义一个子图的密度为边数除以点数。求密度的最大值。

注意到是分数的形式,考虑 分数规划 ,二分答案 \(g\) 。于是我们要求出 \(|E|-g|V|\) 的最大值,根据与 \(0\)的 关系进一步确定区间。

一种比较容易想到的做法:

注意到,如果我们选择了一条边 \((u,v)\) ,那么一定要选择 \(u,v\) 。这种依赖关系恰好对应了 最大权闭合子图 。我们只需要把边也变成点即可。复杂度为 \(O(\log n \times Maxflow(n+m, n+m))\) 。发现点数过于大。

深入利用特殊性质,得到更好的做法二:

因为要应用最小割,所以首先转成最小化的形式:\(g|V'|-|E'|=\sum _{v \in V'} g - \sum_ {e \in E'} 1\)。前面部分无需改变,考虑如何将后面部分与最小割联系。

注意到后面部分就是 \(\frac 1 2 \times \sum _ {v \in V'} d[v] - c[V', V-V']\),左边部分与之前的合并在一起,右边部分就是 \(V',V-V'\) 之间最小割。附加所有节点到\(T\)的边容量为 \(g - \frac {d[v]} 2\)注意,容量有可能为负数,需要增加一个足够大的固定值。 最终,流网络的点数为\(n\)

这个模型很容易推广到带边权与点权的问题。

二分图点权最大独立集&覆盖集。

话说在无向图里,这个问题是NPC的呢。但是二分图就可用最大流跑啦。

覆盖集:\(U \in V\)\(\forall (u,v) \in E, u \in U \vee v \in U\)

独立集:\(U \in V\), \(\forall (u,v) \in E, u \notin U \vee v \notin U\)

发现最小覆盖集和最大独立集互补。只用考虑最小覆盖集。 根据定义很显然啊。

考虑这样建边,新建 \(S\) ,对每个 \(X\) 部的点 \(i\) 连上容量为 \(a[i]\) 的边,边 \((i,j)\) 就要从 \(i\)\(j\)\(\infty\) 的边,每个 \(Y\) 部的点 \(j\)\(T\) 连容量为 \(b[j]\) 的边。

注意到最小割的性质。路径 \(S \rightarrow u \rightarrow v \rightarrow T\) ,至少有一条边被割,不可能是 \(u \rightarrow v\) ,对应到原问题就是 \(u,v\) 中至少选择一个。

所有点权之和减去最小覆盖集就是最大独立集合辣。

应用,论文题:BZOJ1324 Exca王者之剑

一个一般化,基于二元关系的建模方法

适用问题:\(N\) 个元素,每个元素可以选或者不选,有对应的代价。描述若干个二元组,不同关系是产生不同的代价。求中代价的最小/最大值。

找出题目中的二元关系。 有必要时需要附加点。如果出现类似与 \(x\) 选了, \(y\) 必须选的情况,相当于 \(y\) 没选但 \(x\) 选了的代价为 \(\infty\)

具体方法。 新建一个源点 \(S\) 和汇点 \(T\) ,割 \((S,u)\) 表示不选,割 \((u,T)\) 表示选。对于所有二元关系 \((u,v)\) ,在 \((u,v),(v,u)\) 连上容量为 \(e,f\) 的边。根据四种情况可以列方程,解出所有容量,跑最大流即可。

可能出现的情况以及应对方法。解方程后得到中间两条边的容量之和\(K\)为负数,如果图不是二分图,就GG。否则考虑令\(Y\)部的点,与\(S,T\)相连的边的意义交换。可以使中间的容量之和变为\(-K\)

最大权闭合子图,最大密度子图也是这种二元关系建模的特殊应用。

具体参见 彭天翼《浅析一类最小割问题》

容量上下界的可行流

未完待续。

一些好题

BZOJ1305 [CQOI2009]dance跳舞\(n\) 个男生, \(n\) 个女生。有一个 \(n \times n\) 的关系,表示是否愿意一起跳交际舞。每个人最多和 \(K\) 个不喜欢的异性跳舞。每个人不会和一个人跳多次舞。每一轮所有人都要一起跳舞。问最多能进行几轮。

二分+最大流二分图匹配。 显然需要二分答案\(ans\)。考虑将每个点拆分为两个,喜欢\(u1\),不喜欢\(u2\)。考虑\(S\)连向\(u1\)容量\(ans\)\(u1\)连向\(u2\)容量\(K\)。最后,再是喜欢的点对连接,不喜欢的点对连接,容量都为\(1\)。跑最大流,如果\(S\)到所有\(u1\)都是满流的,就可行。

BZOJ3630 [JLOI2014]镜面通道 有两块镜面 \((0,0) \rightarrow (X,0)\)\((0,Y) \rightarrow (X,Y)\) 。中间有若干个正方形和圆形镜面。问最少拿走几块图形,使得左面的光能够通过反射照到最右面。

计算集合+节点容量+最小割。 水能过去,光就能过去。很显然的一个结论吧。。随便感受下就好了。

于是我们需要删除最少的图形,使得左右连通。也即一个割。考虑拆点,建立节点容量,为 \(1\) 。在两连通的两个图形之间,要建容量为无穷的边。下镜面作为 \(S\) ,上镜面作为 \(T\) 。跑最大流即可。

BZOJ1565 [NOI2009]植物大战僵尸 有一个 \(n \times m\) 的矩阵,每个位置有一个植物,每个植物会保护若干个位置。僵尸只能从每一行的最右端开始进攻,而且不能进入被保护的位置。每攻击一个植物,可以获得一个价值(可能为负数),求最后能够获得多少的价值。

拓扑排序,最大权闭合子图。 发现僵尸只能从每一行的最右端开始进攻其实也是一种保护关系,每个植物保护它左边的植物。考虑拓扑排序,对于构成环的节点,我们就删去。对于剩下的DAG,运用经典的最大权闭合子图模型即可。

BZOJ3996 [TJOI2015]线性代数 给出一个 \(n \times n\) 的矩阵 \(B\) 和一个 \(1 \times N\) 的矩阵 \(C\) 。求一个 \(1 \times N\)\(01\) 矩阵 \(A\) .使得 \(D =(A \times B-C) \times A ^ T\) 最大。其中 \(A^T\)\(A\) 的转置。输出 \(D\)\(n \leq 100\)

最大权闭合子图。 一看到题的时候,一脸懵逼。。这个数学题可以用网络流??

其实还是很水的啦。注意到,\(Ans = \sum _{i = 1} ^ {n} \sum_ {j=1} ^{n} A[i] \times A[j] \times B[i][j] - \sum _ {i=1} ^{n} A[i] \times C[i]\)

如果选择了 \(B[i][j]\) 那么一定要选择 \(A[i],A[j]\) ,就是一个最大权闭合子图啦。

算复杂度,点数 \(|V|=O(n^2)\) ,边数 \(|E|=O(n^2)\) 。所以最大流的复杂度是 \(O(n^6)\) ??!!

WTF,复杂度直接爆炸啊!确定自己没有看错??

呐,这个图是二分图诶。。所以复杂度就是 \(O(n^3)\) 啦。。

BZOJ2127 happiness 有一个\(n \times m\)的班级,每个学生会选择文科或者理科,得到不同的喜悦值。如果一个人与前后左右选择的科目相同,可以获得额外的喜悦值。问喜悦值最大为多少。\(n,m \leq 100\)

根据二元关系建图。

做完这道最小割,我整个人都最小割了。。----hzwer

应为要使答案最大化,我们一开始先将喜悦值取负。

加上 \(u,v\) 都选文科的喜悦值为 \(-v1\) ,都选理科的喜悦值为 \(-v2\) ,其他情况下喜悦值为 \(0\) 。可以发现 \((u,v)\) 需要连 \(v1+v2\) 的无向边, \((S,u),(S,v)\)\(v2\) 的无向边, \((u,T),(v,T)\)\(v1\) 的无向边。已经取正数最后减去 \(v1+v2\) ,再除以 \(2\) 即可。

对于每个人自己选择文理科,另外处理。使用同样的技巧,首先把边取负,再加上 \(a[u]+b[u]\) 。最后一起求最小割,减去多余的,取负即可。

BZOJ1834 [ZJOI2010]network网络扩容 给定一个有向图,每条边的容量和费用。每增加一单位容量就会增加一单位费用,求最大流增加\(K\)的最小费用。

很显然的一个费用流建模。考虑首先按照给定的图构造,每条边附加一条容量无限,费用为 $Wi $的边。跑费用流。

如何保证最大流恰好增大到 \(K\) ?求出原来的最大流,附加一个超级汇,限制流量即可。

BZOJ2597 [WC2007]剪刀石头布 给定一个竞赛图,有些边的方向还未确定。定向这些边,使得三元环的个数最多,输出方案。 \(n \leq 100\)

容斥原理,分段费用。 发现正着做很难,考虑 补集转换 。注意到, 一个不满足条件的三元组 \((a,b,c)\) 对应于 \(a,b,c\) 之一的两条出边。

\[ANS = \binom {n} {3} - \sum _ {i = 1} ^ {n} \binom {out[i]} {2}\]

考虑为这些边建立点 \(e[1], e[2], e[3], ...\) 。每个 \(e[i]\)\(T\) 连上容量 \(1\) 费用 \(0\) 的边(容量为 \(1\) 限制它只能作为条边的出边)。

对于边 \((u, v)\) ,如果这条边能够成为 \(u\) 或者 \(v\) 的出边,就连上 容量 \(1\) 费用 \(0\) 的边。

每个点 \(u\) 的流量需要 \(S\) 来提供,根据分段费用的方法,建立 \(n-1\) 条容量为 \(1\) 费用依次为 \(0, 1, 2, 3, ..., n-2\)的边。

跑费用流。考虑复杂度,点数 \(O(n^2)\), 边数 \(O(n^2)\), 至多增广 \(O(n^2)\) 次,总的复杂度 \(O(n^6)\)。实际上,由于图较为稀疏,所以使用SPFA的费用流达不到这个上界。

LRJ的模版好慢啊啊啊,卡了半天常数。。。有时间学学ZKW费用流QAQ

BZOJ3171 [TJOI2013]循环格 有一个 \(n \times m\) 的矩阵,每个元素表示了一个方向(上下左右)。问最少改变多少元素的方向,使得从任意位置出发,按照元素的方向运动,最后能到达原来的位置。 \(n \leq 15\)

环的性质,费用流建模。 考虑环的性质: 所有节点的出度和入度都为 \(1\) 考虑拆点,\((x,y,1),(x,y,2)\)\(S\) 连向每个 \((x,y,1)\) 容量为 \(1\) 费用为 \(0\) 的边。 \((x,y,1)\) 向四周的 \((x',y',2)\) 连上容量为 \(1\) 费用为 \(1\) (当与原来方向相同时为 \(0\) )的边。所有 \((x,y,2)\) 连向 \(T\) 容量为 \(1\) 费用为 \(0\) 的边。跑最小费用最大流。

注意到,费用最小的前提的是 流量最大,所以与 \(S,T\) 相连的边一定是满流的(很显然一定能做到)。 这样就能够限制每个位置的出度入度都为 \(1\)

BZOJ2879 [NOI2012]美食节。\(n\) 种菜和 \(m\) 个厨师,厨师 \(j\) 烧菜 \(i\) 所需的时间是 \(t[i][j]\) ,一个厨师一次只能烧一样菜。现在知道有 \(p[i]\) 个学生需要第 \(i\) 道菜。求所有学生所需要的等待时间总和的最小值。 \(n \leq 40, m \leq 100, \sum p[i] \leq 800\)

神奇的费用流建模,动态加边。 显然需要划分为两部分点。

一开始的错误想法:建立 \(n\) 个点 \(a[1], a[2], a[3], ...\)\(S\) 连向这些点容量 \(p[i]\) 费用 \(0\) 的边。为厨师建立点 \(b[1], b[2], b[3], ..., b[m]\) 连向 \(T\) 容量为 \(1\) 费用为 \(0\) 的边。所有 \(a[i], b[j]\) 连接 容量无限, 费用 \(t[i][j]\) 的边。每一次增广后,我们得到了 \(S \rightarrow a \rightarrow b \rightarrow T\) 的路径。相当于厨师选择烧这样菜。然后我们再连接 \(b[j]\)\(T\) 的边,容量仍然为 \(1\) , 费用要增加先前的时间。

呐,看上去没错啊?怎么会比答案少呢??事实上就是因为费用流算法存在反向边,目的是 退流 。所以一定程度上网络流也是贪心??然后退流就是经典的 反悔操作 。这就使得这个算法中存在后效性(退流之后,新的边就不合法了)。

考虑一种新的权值计算方式。 假设一个厨师烧菜时间的序列: \(t1, t2, t3, ..., tn\) 那么总共的时间为 \(n \times t1, (n-1) \times t2, ..., tn\) 。考虑倒着计算,依次加入 \(k \times t\) 的边。

拆点!为了使 \(1\) 倍时间, \(2\) 倍时间,等,都只计算一次。考虑将每个厨师拆成 \(\sum p[i]\) 个点,依次表示烧倒数第 \(k\) 条边。然而这么多边建出来会T啊。考虑动态建边,当一次增广,烧完倒数第 \(k\) 道菜,加入倒数第 \(k+1\) 道菜。

计算一下复杂度。需要增广 \(O(\sum p[i])\) 次,点数始终保持 \(O(n+m)\) 个, 边数始终保持 \(O(nm)\) 条,于是总的复杂度为 \(O((n+m)nm \times \sum p[i])\)SPFA-EK费用流卡着时限过QAQ。看来要学ZKW费用流了QAQ。

BZOJ1001-[BeiJing2006]狼抓兔子。 给定一个平面图,求最小割。

平面图转对偶图。 此题暴力ISAP可过。不过经典的做法是,求出他的对偶图(区域变成新的点,相邻连边)。于是跑最短路就好了。

BZOJ2400-Optimal Marks。 给定一个无向图,某些点的权值已经知道,请确定剩下点的权值。定义一个图的代价为所有边两端点权的异或值之和。求无向图的最小代价,当代价最小时,最小的点和。

按位拆分,最小割。 显然可以按位拆分。显然可以最小割。S集的权为0T集的权为1。如果是已经确定的位,就与S or T连上流量为INF的边。原图连流量为1的边。

比较不显然的是最小点权和。最小费用最大流?TLE!

这里有一个Trick。我们把所有的流量1改为1000。对于所有与S没有直接连边的点,连上流量为1的边。当割最小时,先要满足价值最小,其次满足点权和。

BZOJ1280-Emmy卖猪pigs。 有若干个猪圈,猪圈里养了若干头猪。依次来了几位客人,每位客人带上了若干个猪圈的钥匙,他最多可以买 \(ai\) 头猪。之后,你可以把这些猪圈中的猪任意安排,再关上。问最多能卖多少猪?

经典最大流建图。 不难发现一个性质:当一个猪圈中已经有一个客人来过后,第二位客人能够买前一位客人能卖的猪。于是建图就很simple了:

每个猪圈(源点)向到这个猪圈的第一位客人连流量为猪的数量的边,每个客人向后续有重叠的客人连流量为无穷的边。每位客人向汇点连容量为 \(ai\) 的边。

BZOJ1449-[JSOI2009]球队收益\(n\) 支球队,每支球队已经赢了 \(win[i]\) 场,输了 \(lose[i]\) 场,每支球队还有参数 \(c[i],d[i]\) 。剩下的球队会进行 \(m\) 场比赛。问所有球队的价值总和的最小值。一个球队的价值定义为 \(c[i] \times win'[i] + d[i] \times lose'[i]\) (代表最终的胜利,失败的场数)。

拆边费用流。 发现一场比赛对应两个价值,但是流量无法凭空产生,那么该如何建图呢?

有一个很秒的想法,注意到每只队伍最终胜利和失败的次数的总和是比边的。首先假设剩下的场数都是输的,然艘计算每多胜一场可以增加的权值。由因为这个增量是显然递增的,所以是正确的。

BZOJ3280-小R的烦恼 你需要一些xx,第 \(i\) 个商店有 \(li\) 个xx,每个xx要 \(pi\) 的代价。你在第 \(i\) 需要 \(ai\) 个xx。每个xx在用完一天之后会XX,所以,拿去修理它,第 \(i\) 个地方,需要修理 \(d\) 天,需要 \(qi\) 的花费。求最小需要花的前。

奇妙的费用流。 注意到,一个xx可以有多次贡献,对应到流里面,流量并不会增加,这样应该如何建图?注意到,每天结束后有固定 \(ai\) 个死掉的xx,这个流量可以由原点提供,于是我们就得到建图方式辣。注意到要考虑:每天多出来死的;活的到汇点;第一天新来活的;每天把死的修d天变成活的;前一天活的不用,到后一天;前一天死的不修,到后一天。。貌似这样不太好QAQ,大概就这这样理解啦。 建图如下表:

起点 终点 流量 费用
0 dead[i] a[i] 0
live[i] 2*n+1 a[i] 0
0 live[1] l[j] p[j]
dead[i] live[i+d[j]] q[j]
live[i] live[i+1] 0
dead[i] dead[i+1] 0

BZOJ5120-[2017国家集训队测试]无限之环\(n \times m\) 的方格,每个方格的上下左右,有可能存在接口,也有可能没有。可以顺时针或逆时针旋转。问最少操作几次,使得每个接口总有一个接口与之连通。很显然,总共存在15种方块(不算空的)。

二分图,费用流。 注意到 网格图是一个二分图 所以考虑黑白染色,就变成了两部分的连接。很显然拆成四个方向的四个点,首先对应接触的点先连接,考虑源点流向X集。

由于每部分的流量总量不变。所以考虑S流向默认的接口 \((1,0)\) 的边。而旋转就是接口之间,花费一定的费用来转移流量。

以只有一个接头为例。首先S连向那个接头 \((1,0)\) 的边,然后那个接头连向两边 \((1,1)\),向对面连 \((1,2)\) 的边。

相邻的两个接头也类似,三个接头的与一个接头的恰好相反。

注意空方块和四个接头的没有必要旋转。

注意那个对面的两个接头的不能旋转。。因为出题人也建不出图。。hhh。。

这个建图嘛,我手撸了1h。共6k,竟然1A了。哈哈哈。

猜你喜欢

转载自www.cnblogs.com/cyanic/p/9159441.html