网络流24题整理

部分转载自哪里我也忘了,侵删。 /xk

搭配飞行员

二分图最大匹配,最大流。

在二分图的基础上增加源点 \(S\) 和汇点 \(T\)

  1. \(S\)\(X\) 集合中每个顶点连一条容量为 \(1\) 的有向边。
  2. \(Y\)集合中每个顶点向 \(T\) 连一条容量为 \(1\) 的有向边。
  3. \(XY\)集合之间的边都设为从 \(A\) 集合中的点到 \(B\) 集合之中的点,容量为 \(1\) 的有向边。

直接二分图最大匹配即可。
也可求网络最大流,流量就是匹配数,所有有流量的边是都是一组可行解(判断各边是否有流量,即判断反向边的权值是否不为0)。

太空飞行计划

最大权闭合图,最小割。

最小割=最大流。
闭合子图:对于一个有向图 \(\mathrm {G = \langle V,\,E \rangle}\),存在点集合 \(\mathrm S\),任取点 \(u \in {\mathrm S}\) 的出边的另一个点也属于 \(\mathrm S\) ,则为闭合图。
最大权闭合子图:\(\forall u \in \mathrm {V}\),都有一个权值函数 \(\operatorname{w}(u)\),如果存在一个点集 \({\mathrm S \subseteq \mathrm G}\),使得 \(\sum_{u \in {\mathrm S}}\operatorname{w}(u)\)最大,则称 \(\mathrm S\)\(\mathrm G\) 的最大权合子图。

把每个实验看作二分图 \(X\) 集合中的顶点,每个设备看作二分图 \(Y\) 集合中的顶点,增加源点 \(S\) 和汇点 \(T\)

  1. \(S\) 向每个 \(X_i\) 连接一条容量为该点收入的有向边。
  2. \(Y_i\)\(T\) 连接一条容量为该点支出的有向边。
  3. 如果一个实验 \(i\) 需要设备 \(j\),连接一条从 \(X_i\)\(Y_j\) 容量为无穷大的有向边。
    统计出所有实验的收入之和 \(tot\),求网络最大流 \(flow\),最大收益就是 \(tot-flow\)。对应的解就是最小割划分出的 \(S\) 集合中的点,也就是最后一次增广找到无法增广时能从 \(S\) 访问到的顶点。

其实要使收益最大,即 \(tot-flow\) 最大,但 \(tot\) 为定值,所以当 \(flow\) 最小,即 \(flow\) 为网络最小割的时候收益最大。直接用 dinic 求最大流即可。

最小路径覆盖

有向无环图最小路径覆盖,最大流,拆点。

最小路径覆盖的定义就是每次可以从任意点出发,用尽可能少的不相交的路径覆盖掉整张图。(最小路径覆盖只适用于有向无环图)

构造二分图,把原图每个顶点 \(i\) 拆分成二分图 \(X,Y\) 集合中的两个顶点 \(X_i\)\(Y_i\)。对于原图中存在的每条边 \((i,j)\),在二分图中连接边 \((Xi,Yj)\)。然后把二分图最大匹配模型转化为网络流模型,求网络最大流。

最小路径覆盖的条数,等于该二分图上的最小未匹配数,即总点数减去最大匹配数。

魔术球

最大流,最小路径覆盖,二分图最大匹配。

把每个柱子当成一条路径,能构成完全平方数的两个数当成连通的两个点最大流/二分图最大匹配的模型就构建好了。(最小路径覆盖转化为最大流,该图上的最小路径覆盖就是最优方案)
从大向小建图,这样每次就不用初始化了 因为二分匹配的实质就是更改以前的匹配当不会更改最优的情况时,才更改匹配。所以如果不是最优则不会更改匹配 所以以前的最优匹配也不会因后加入的节点而更改,那么枚举球的数量即可。当独立子集数大于 \(n\) 时结束。
用匈牙利算法求得二分图最大匹配。

这题有明显的贪心解法,图论模型不明显,网络流建模也不好判断,属于一种隐式图模型。

圆桌聚餐

二分图多重匹配,最大流。

二分图的左边是单位,右边是桌子。由于题目的限制,每个单位只能在一个桌子坐一个人。所以我们就把每个单位向各个桌子连一道流量为 \(1\) 的边,这样每次流一次一个单位只能贡献 \(1\) 个流量,也就是一个人到一个桌子上,然后由超级源点与每个单位连接,边的权值为单位人数由每个圆桌与超级汇点连接,边的权值为圆桌人数。然后跑一下最大匹配,如果最大匹配数等于所有单位的人数和,那么就可以完全安排,否则不能完全安排。

最长递增子序列

最大流,DP,拆点

\(1\) 问是动态规划,第 \(2,3\) 是网络流。我们可以想出这样一个模型:把后面较大的数和前面较小的数连边,然后针对每个长度为 \(s\) 的序列第一个数与汇点连,最后一个数与源点连,然后跑最大流就行了。
后面较大的数和前面较小的数连边,可以 dp 的时候顺带解决。主要是找序列的第一个数和最后一个数,所以我们两次 dp:第一次处理从数i向前最长的非降子序列(即 \(f_i\)),第二次处理从数i向后最长的非降子序列(即 \(g_i\))。
\(f_i=s\),源点与 \(i\) 连;
\(g_i=s\),汇点与 \(i\) 连;
\(2\) 问连边容量都为 \(1\),第 \(3\) 问在第二问基础上把源点与最后一个数,第一个数与汇点连边容量改为无穷大。
直接 dinic 求个最大流就行了。

试题库

二分图多重匹配,最大流

与圆桌问题类似。
设置超级原点 \(S\) 和超级汇点 \(T\),将所有的试题类型与超级源点相连,在对应的要求和试题之间连容量为 \(1\) 的边,然后将题库中每个试题都拆点,这样保证每个试题都只选一次,然后入点连接所属类型,出点连接超级汇点就可以了,从源点开始判断所有出边,若有容量未满的边就是无解情况,否则像圆桌问题一样将所得答案排序后输出。输出的时候加个 \(pre\) 数组表示当前边属于哪个试题。
直接跑 dinic 求最大流就行。

方格取数

二分图最大权独立集,二分图染色,最小割。

二分图最大权独立集:在二分图 \(\mathrm G = \langle \mathrm{X,\,Y,\,Z} \rangle\) 中,选取一个点集 \(\mathrm V \subseteq \mathrm G\),使得 \(\forall u,\,v \in \mathrm V\),有 \(u \not \to v\),则称 \(\mathrm V\) 为原图的一个独立集,在满足上述条件的基础下,最大化 \(\mathrm V\) 的大小,此时则称 \(\mathrm V\) 是二分图 \(\mathrm G = \langle \mathrm{X,\,Y,\,Z} \rangle\) 的一个最大权独立集。

一般的,我们有最大权独立集点数等于总点数减去最小顶点集覆盖。

首先把棋盘黑白染色,使相邻格子颜色不同,所有黑色格子看做二分图 \(X\) 集合中顶点,白色格子看做 \(Y\) 集合顶点,建立超级源点 \(S\) 超级汇点 \(T\)

  1. \(S\)\(X\) 集合中每个顶点连接一条容量为格子上的数的有向边。
  2. \(Y\) 集合中每个顶点向 \(T\) 连接一条容量为格子上的数的有向边。
  3. 相邻黑白格子 \(X_i,Y_j\) 之间从 \(X_i\)\(Y_j\) 连接一条容量为无穷大的有向边。
    求出网络最大流,结果就是所有格子中的总数值和减去最大流量(最小割)。

餐巾计划

费用流,后效性模型。

网络流模型里也有当前决策会影响下一步决策的情况,即为后效性模型。
首先,因为我们每一天都要使用干净餐巾,又会制造脏餐巾,所以我们将一天 \(d_i\) 拆成两个点 \(d_i'\)\(d_i''\),可以对应看做早上和晚上,每一天早上我们会收到干净餐巾,每一天晚上我们会向后发送脏餐巾。
然后,每一个 \(d_i''\) 都向 \(d_{i+1}'\) 连容量为 \(r_i\),费用为 \(0\) 的边,代表每一天早上可以接受上一天晚上的脏餐巾。其次,每个 \(d_i'\) 都要向 \(t\) 连一条容量为 \(r_i\),费用为 \(0\) 的边,表示每一天的需求 \(r_i\) 。再其次,我们从每一个 \(d_i''\)\(d_{i+1}''\) 连容量为 INF,费用为 \(0\) 的边,代表可以将当天的脏餐巾预留给下一天晚上。接着,我们处理购买餐巾的情况,从 \(s\) 向每一个 \(d_i'\) 连容量为 INF,费用为 \(p\) 的边,代表购买餐巾,要花费 \(p\) 元。再然后,我们从每个 \(d_i'\)\(d_{i + m}''\) 连容量为 INF,费用为 \(f\) 的边,代表送到快洗店。同理,我们从每个 \(d_i'\)\(d_{i + n}''\) 连容量为 INF,费用为 \(s\) 的边,代表送到慢洗店。
跑最小费用最大流,费用即为答案。

后效性模型的操作是找到存在后效性的节点,然后对其操作。

软件补丁

最小转移代价。

Is this 网络流?最小转移代价说白了就是一个特殊处理的最短路。
这个题很多这个属于那个,状态很多,其实明白了属于关系之后,直接状态压缩就行了,然后压缩完状态之后直接跑一个分层图最短路就行了。

数字梯形

最大权不相交路径,费用流。

源点向顶端的每一个数建边,流量为 \(1\),费用为 \(0\),然后就是每个数字向左下和右下建边,流量为 \(1\),费用为 \(0\),以及底向汇点建边,流量为 \(1\),费用为 \(0\),由于有路径不能相交,即每个点只能走 \(1\) 次这样的限制,所以每个点要拆点,中间连一条流量为 \(1\),费用为数字的边。
这是条件 \(1\) 的,条件 \(2\) 的话只需要将拆点中间的边流量改成 INF,以及底向汇点的流量设为 INF 即可。
条件 \(3\) 的话在条件 \(2\) 基础上把每个数字向左下和右下建的边流量设为 INF 即可。

运输问题

费用流。

求一个最小费用最大流和最大费用最大流,模板题。
把所有仓库看做二分图中顶点 \(X_i\),所有零售商店看做二分图中顶点 \(Y_i\),建立附加源点 \(S\) 汇点 \(T\)

  1. \(S\) 向每个 \(X_i\) 连一条容量为仓库中货物数量 \(a_i\),费用为 \(0\) 的有向边。
  2. 从每个 \(Y_i\)\(T\) 连一条容量为商店所需货物数量 \(b_i\),费用为 \(0\) 的有向边。
  3. 从每个 \(X_i\) 向每个 \(Y_j\) 连接一条容量为无穷大,费用为 \(c_{i,j}\) 的有向边。
    最小费用流值就是最少运费,最大费用流值就是最多运费。

分配问题

二分图最佳匹配,费用流。

建立源点 \(S\) 和汇点 \(T\),根据人和工件构建出二分图。设人为 \(X_i\),工件为 \(Y_i\),对于源点汇点,进行一下建图:

  1. \(S\) 到每个 \(X_i\) 建一个流量为 \(1\),费用为 \(0\) 的有向边。
  2. \(Y_i\)\(T\) 建一个流量为 \(1\),费用为 \(0\) 的有向边。
  3. 从每个 \(X_i\) 到每个 \(Y_j\) 建一个流量为 \(1\), 费用为(求最大效益则为正,反之则为负)的有向边。
    可以看出费用流是负数的时候也可以求东西。

负载平衡

费用流。
建立源点 \(S\) 和汇点 \(T\),根据仓库和储存量来建图,主要问题就是储存量的计算以及搬运量的计算。
三种建边方式:

  1. \(S\) 向仓库建边,流量为初始存储量,费用为 \(0\)
  2. 从仓库向相邻仓库建边,流量为 INF,费用为 \(1\)
  3. 从仓库向 \(T\) 建边,流量为平均存储量,费用为 \(0\)

可以求出最小费用即为最小搬运量。

最长 k 可重区间集

最大权不相交路径,费用流。

费用流模型:流量控制;
乍一看不像是费用流,要往费用流上想。所以\(k\) 一定是个容量,区间长度一定是个费用。
那么有以下两种建图(需要离散化):

  1. 将直线上的点离散化成 \(1\)\(2n\),从头到尾连接起来,容量为 \(k\),费用为 \(0\)
  2. 每条线段起止点连接起来,容量为\(1\),费用为区间的长度。

此时最大费用即是答案。(这道题中用主干流上的流量来表示还可以被覆盖的次数,每次脱离主干流时流量减一费用加上对应权值,汇入主干流后流量又增加。)

星际转移

分层图,最大流,费用流。

源点是地球,然后中间一串的空间站,最后连向汇点月球。
空间站间各自连边,流量是飞船的容量空间站间各自连边,流量是飞船的容量,这样跑最大流跑出来的其实是一天能到的最多的人,不能满足要求。我们需要的是一个类似分层图的东西。按照时间分层,就能表示 \(x\) 天的最大流。每天的图都是地球-空间站-月球每天的图,那么
源点向每一天的地球连边,容量 INF ;
每一天的月球向汇点连边,容量 INF;
对于每个飞船,前一天的位置向后一天位置连边,表示时间的流逝,容量是飞船容量;
对于每天的空间站向下一天的这个空间站连边,容量 INF,表示人可以停在这个空间站。

孤岛营救

分层图最短路。

混进来的状态压缩最短路。一道状态压缩 BFS,也可以用分层图 SPFA 和状态压缩做。
由于 \(p\) 很小,所以状压 BFS 即可。状压的是当前捡到的钥匙种类。
以及,虽然两个格子时间不会有多扇门,但是一个格子上可能有多个钥匙。

航空路线

最长不相交路径,费用流。

对于每个点拆成 \(A_i\)\(B_i\) 两个点,两个点之间的容量为 \(1\),边权为 \(1\),(因为每个点只能选一次,每选一个点可以对答案造成 \(1\) 的贡献;若 \(i\)\(1\)\(n\) 容量应为 \(2\),因为这两个点可以选两次)
对于每条从 \(u\)\(v\) 的边,让 \(B_u\)\(A_v\) 建一条容量为 \(1\),边权为 \(0\) 的边(因为每条边只能选一次,选边并不会对答案造成影响)
最后从源点向 \(A_1\) 建一条容量为 \(2\),边权为 \(0\)的边。从 \(B_n\) 向汇点建一条容量为 \(2\),边权为 \(0\) 的边,跑最大费用最大流即可。
输出城市(两次 dfs):
第一次 dfs 找到一条 \(1\)\(n\) 所有边的 \(flow\) 都为 \(0\) 的路径正序输出,
第二次 dfs 找到另一条 \(1\)\(n\) 所有边的 \(flow\) 都为 \(0\) 的路径倒序输出。

汽车加油行驶问题

分层图最短路,费用流。

分层图最短路做的。

我们按耗油量划分层数,对于每一个点 \((now,x,y)\)\(now\) 表示档期用了多少油,即划分层数 \(x,y\) 表示点在当前层的位置,而点 \((now,x,y)\) 可以向 \((now+1,x+1,y),(now+1,x,y+1),(now+1,x−1,y),(now+1,x,y−1)\) 连边,具体权值按题目要求即可;对于每个点都如此连边即可。
但有一些需要注意的:

  1. 如果当前点 \((now,x,y)\) 有加油站,那么需要在 \((now,x,y)\)\((0,x,y)\) 连接一条边即可。
  2. 如果当前点已耗油 \(k\),即当前点为 \((k,x,y)\),并且没在上一种情况中处理,那么需要新建一个加油站,即从 \((k,x,y)\)\((0,x,y)\) 连一条权值为 \(a+c\) 的边,因为新建的加油站是不包含加油费用的。
  3. 一个相对容易忽略的细节,就是在情况 \(1\) 中,如果油已经满了,即 \(now=k\),需要向周围连边,如果你不连边,那么你就只能在每一个节点新建加油站,而不能利用已有的加油站,因为你没有从有加油站的点走出来。

深海机器人

多源多汇,费用流。

建两组边,然后就是确定边的优先级。
\(S\) 向所有机器人起点连边,所有机器人终点向 \(T\) 连边。
每个点向右向下分别连两条边,一条容量为 \(1\),边权为图中边权;另一条容量为 INF,边权为 \(0\)
这样保证了权值只能获得一次,又保证了这条边可以被多个人走。

火星探险

拆点,费用流。

把每一个格点拆分成两个点(表示:点 \(1\) 表示进入该格子,点 \(2\) 表示出来该格子),并且把点 \(1\) 和点 \(2\) 连接一条有向边:
当这个点有岩石时,容量为 \(1\),费用为 \(1\)
当这个点不是岩石时,容量为 INF,费用为 \(0\)
把每一个格点的点 \(2\) 与其相邻的点的点 \(1\) 连接一条容量为 INF,费用为 \(0\) 的边,然后只要把费用取相反数,然后跑最小费用最大流即可。

骑士共存

二分图最大独立集,最小割。

和方格取数几乎一模一样,就是可以取八个方向。

\(s\) 向所有黑点连容量为 \(1\) 的边,所有白点向 \(t\) 连容量为 \(1\) 的边,然后每个黑点向能攻击到的点连容量为 INF 的边,最后用总格数减去删除的格子再减去最小割就是答案。

最长 k 可重线段集

最大权不相交路径,费用流。

与最长 \(k\) 可重区间集问题非常相似,但是会有垂直于 \(x\) 轴的线段的情况。
所以要把直线上每个点分成左部分和右部分,垂直于 \(x\) 轴的线段从一个点的左部分连到右部分。其它线段从左端点的右部分连道右端点的左部分。
其余操作与最长 \(k\) 可重区间集问题相同。

posted @ 2023-01-18 09:11  离弦  阅读(59)  评论(0)    收藏  举报