1.15 上午-网络流
前言
勿让将来,辜负曾经
我爱网络流,哇哦哇哦——争取一千字以内秒完(不算代码、公式)
这里声明一点,考虑到网络流题目的独特性,接下来的“一题一解”部分将不会给出代码(也许会给一些代码的实现细节)
正文
知识点
其实网络流的东西还是不少的,如果扯远了云落能噼里啪啦说五千字
老规矩——博客安利时间——传送门
但是这个比较古老了,里面少了很多东西(预流推进算法、各种时间复杂度证明、上下界网络流、费用流的 dijkstra 写法以及证明、势能函数的引入、网络流的线性规划理解)
但其实作为一个黑盒算法,目前只需要掌握一些较为基础的东东即可,云落认为上这篇古老的博客可以支撑诸位顺利食用接下来的题目咯,诸位觉得捏?
一题一解
T1 【模板】网络最大流(P3376)
素板,速切(EK,Dinic,ISAP,HLPP 均可,写 HLPP 的可以去 P4722 蹭个双倍经验)
T2 方格取数问题(P2774)
云落可能比较喜欢网络流,做多了有点感觉。对于这种方阵上面的相邻格子操作或者约束问题,通常考虑黑白染色转化为二分图结构,进而添加超级源点和超级汇点,简单转化为一个 最大流/最小割 问题
这道题目就很典,黑白染色是经典套路。求最大和转化为整体减去删去的最小和,进而发现这是一个类似最小割的问题,直接做做完咯
网络的构建——
我们称 \(x+y\) 是奇数的格子为黑格,反之则为白格
首先源点向黑格连边,容量显然为格子上的数;白格向汇点连边容量同样是格子上的数
然后对于所有黑格,向它的四联通范围内每个格子连边,容量为 \(+ \infty\)
对于上述所有连边,相应地建立其反向边即可
答案是所有的格子的和减去最小割
T3 文理分科(P4313)
文理俩字都拍在这里了,是不是很容易想到 \(S-T\) 割的概念?
求最大值,直接用上题类似的容斥套路,所有权值刨除最小割
如何构造网络?
大致有一个想法,如果一条边被割开,说明其对最小割造成了贡献,在题目中表现为这个决策不成立(注意最小割求的是刨去的未选的权值)
自然地,连边大概也类似上一道题目,云落钦定源点向学生连边,容量为文科贡献;同学向汇点连边,容量为理科贡献
组合贡献如何呈现在网络上?
以文科为例,大胆猜测其连边与源点和其四联通范围内的其它点有关。回到我们的问题,求最小割——求最少的刨除权值
组合贡献不被计入最小割中,当且仅当 \((x,y)\) 以及四联通范围内的点同时不被计入最小割。换言之,只要存在一个人不选文,那么组合贡献就无法贡献给答案,也就是会贡献给最小割
那么,一个比较自然的想法:还是以文科为例,对于 \((x,y)\) 考虑新建一个结点,表示 \((x,y)\) 与四联通范围内共同给出的组合贡献。源点指向这个新点,容量为组合贡献的权值。新点指向 \((x,y)\) 以及四联通范围内的所有点,容量为 \(+ \infty\)
仔细思考之后发现这么拍脑袋想出来的做法是有正确性的,于是乎相应的把理科的边建出来就做完了……
T4 最长不下降子序列问题(P2766)
我嘞个七拼八凑……
第一问 \(O(n^2)\) DP,神犇要是想炫技也可以写 \(O(n \log n)\) 的做法,但请问接下来的两问又该如何完成捏?
二三问其实并不好看出来(反正网络流的题目没有一道长得像网络流的)
首先朴素 DP 似乎不是很好解决这个问题,且这个问题是一个最值问题。一个解决最值问题的 trick——可以蒙一蒙算法,就按这个顺序——贪心 \(\to\) 二分 \(\to\) 动态规划 \(\to\) 最短路 \(\to\) 网络流……
前面的路云落已经帮诸位淌过一遍了,直接进入正题
二三问都是“最多”,并且似乎没有显然的容斥,考虑最大流
比较 naive 的是中间的结点构造,自然是一个 \(i\) 对应一个结点。然后就寄了,因为有一个非常恶心的约束,叫做每种元素至多选一次,但这个技巧也比较常见——拆点!
(浅浅吐槽一句,似乎除了特别水的网络流,云落还没有见过什么网络流的题目不需要拆点的……)
把一个 \(i\) 劈成两半,两个点之间建立一条容量为 \(1\) 的边
然后就是源点汇点的连边技巧——我们要求的是最大流,也就是说一定在题目中会出现一些东东作为限制最大流出现的约束。这显然是最长不降子序列的限制
那么,当结点表示 \(i\) 的时候,我们考查一条增广路的实际含义,表示一条合法的最长不降子序列
自然地,源点发射出去的边应当指向子序列的起始位置,而指向汇点的结点应当为子序列的末尾位置。网络构建很显然咯,对于所有的 \(f_i==1\),源点向(拆点后的)左点连一条容量为 \(1\) 的边;同理,(拆点后的)有点向汇点连一条容量为 \(1\) 的边
那么中间的部分也就呼之欲出了,对于每一个 \(j < i\),如果有 \(a_j \le a_i\),那么就右点 \(j\) 指向左点 \(i\)
T5 【模板】最小费用最大流(P3381)
板,随便把 BFS 改成 SPFA 即可
T6 志愿者招募(P3980)
真的就差一点点就上线性规划了……这个题目出的是真的花
说实话这个题目要不是样例强云落都不知道自己想假了……
还是直接上网络流,不考虑那么多(赛场上还是先考虑 DP 什么一些比较正经的做法比较好)
比较大众化的错误就是,源点连志愿者,然后志愿者连其控制的时间区间,最后时间连汇点,然后跑费用流
但这么做会寄,因为志愿者不是想什么时候停就什么时候停的,而是一旦选择这个志愿者,他会兢兢业业地完成他所控制的时间区间内的所有任务……
按照上述的假做法,会得到 \(0pts\) 以及样例不过的优秀成绩,可喜可贺!
所以,我们需要重新去思考这个问题
正难则反,其实也不是完全反过来——当不好从志愿者的角度切入时,不妨考虑从时间线的角度切入
然后其实就做完了,网络构造的方式如下:
源点指向第一天,容量 \(+ \infty\),费用为 \(0\)
最后一天指向汇点,容量 \(+ \infty\),费用为 \(0\)
中间的部分时间线 \(i\) 向 \(i+1\) 连边,容量 \(+ \infty - a_i\),费用 \(0\)
这很好理解,我们需要一些带权边(志愿者)补齐 \(+ \infty\)
然后就是 build(l,r+1,inf,c)
,表示一个志愿者
这道题目的难点在于志愿者向时间线的转化,剩下的构建网络的部分并不难搞
T7 交换棋子(P3159)
又是一道长的不像网络流的网络流……
题意小转化:棋子交换可以视为黑子在棋盘上的移动
直接朴素做费用流会寄,原因是这样的。我们考查一个黑子的完整移动路径,起止点的流量消耗都是 \(1\),而路径上的点流量消耗都是 \(2\),显然直接做假完了——
所以,考虑拆点
干脆就拆的彻底一点,直接一变三,左点表示交换进来,中点是原有的点,右点表示交换出去,然后剩下的就比较显然了,建图跑最大流即可
还是简述一下建图的形式吧!
-
源点指向初始点中点,容量 \(1\) 费用 \(0\)
-
结束点中点指向汇点,容量 \(1\) 费用 \(0\)
-
如果某结点初末状态相同,\(l \to mid\) 容量 \(\frac{lim}{2}\),费用 \(0\),\(mid \to r\) 容量 \(\frac{lim}{2}\) 费用 \(0\)
-
初状态黑点,末状态白点(需要将黑子交换出去),\(l \to mid\) 容量 \(\frac{lim}{2}\),费用 \(0\),\(mid \to r\) 容量 \(\frac{lim+1}{2}\) 费用 \(0\)
-
初状态白点,末状态黑点(需要将黑子交换进来),\(l \to mid\) 容量 \(\frac{lim+1}{2}\),费用 \(0\),\(mid \to r\) 容量 \(\frac{lim}{2}\) 费用 \(0\)、
-
对于每个结点,向其八连通范围内所有结点连边,容量 \(+ \infty\) 费用 \(1\)。需要注意的是,这条边的起点是结点的右点,中点是八连通结点的左点
然后直接跑费用流即可
T8 航班安排(P4452)
求最大收益,要求尽可能多的接订单(题干没写……),考虑费用流,具体地,是考虑最大费用最大流
订单显然是网络流里的结点,注意到订单只能被接受一次,所以考虑拆点,并连带而来的就是建边,容量 \(1\),费用 \(c_i\)(代码实现中应该写成 \(-c\),因为要求最大费用,所以取相反数)
然后就是源点向左点连边,右点向汇点连边,容量都是 \(1\)(一架飞机)。源点发射出去的边的费用是 \(-f_{1,i}\)(而在代码实现中应该写成 \(f_{1,i}\),原因同上),汇点接受的边费用是 \(-f_{i,1}\)(代码中取反,原因同上)
Warning:题目中说基地机场编号为 \(0\),但云落不是很习惯,所以整体偏移了一下下……
剩下的就是暴力枚举订单,如果能在订单 \(i\) 之后衔接订单 \(j\)(反之亦然),直接连边,容量 \(1\),费用 \(-f\)(代码取反,理由同上)
剩下的就是费用流
T9 小凸玩矩阵(P4251)
第 \(k\) 大,二分答案是显然的
转成二分图,左行右列,对于二分出的 \(mid\),如果 \(a_{i,j} \le mid\) 就连边,跑二分图匹配
当然,最大流也能解决这个问题
最简单的一集
后记
完结撒花!