网络流练习
作者:互联网
网络流练习
若是一个点经过的次数有限制,则需要拆点
拆点的妙用博大精深
注:下文中 \(s\) 指超级源点,\(t\) 指超级汇点
最大流
P1231 教辅的组成
题意:
现在有 \(a,b,c\) 三种东西,分别有 \(n1,n2,n3\) 个
告诉你 \(m1\) 组 \(a,b\) 的对应关系,\(m2\) 组 \(a,c\) 的对应关系
只有 \(a_i\) 同时对应 \(b_j\) 和 \(c_k\),\(a_i\) 才能和 \(b_j\) 与 \(c_k\) 配成一套
问在不重复的条件下最多可以配成几套
思路:
很基础的最大流
由于 \(a\) 对应 \(b\) 和 \(c\) ,考虑建图时把所有 \(a\) 放中间 \(b,c\) 放两边
从 \(s\) 向所有 \(b\) 连一条容量为 \(1\) 的边,从所有 \(c\) 向 \(t\) 连一条容量为 \(1\) 的边
从所有 \(b\) 向所有 \(a\) 连一条容量为 \(1\) 的边,从所有 \(a\) 向所有 \(c\) 连一条容量为 \(1\) 的边
跑最大流就行
但是我 \(Wrong\ Answer\) 了 \(QAQ\)
这是因为 \(a\) 在中间,若是像下面一样会算两次:
so,我们把中间的所有 \(a\) 拆成两个点,加一条容量为 \(1\) 的边
最大流即为答案
P2472 蜥蜴
题意:
在一个 \(r\) 行 \(c\) 列的网格地图中有一些高度不同的石柱,第 \(i\) 行 \(j\) 列的石柱高度为 \(h_{i,j}\)。
一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外。
每行每列中相邻石柱的距离为 \(1\),蜥蜴的跳跃距离是 \(d\),即蜥蜴可以跳到平面距离不超过 \(d\) 的任何一个石柱上。
石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减 \(1\)(如果仍然落在地图内部,则到达的石柱高度不变)。
如果该石柱原来高度为 \(1\),则蜥蜴离开后消失,以后其他蜥蜴不能落脚。
任何时刻不能有两只蜥蜴在同一个石柱上。
思路:
数据范围很小,考虑网络流
因为每个石柱都有经过次数限制,所以要位置 \(i\) 拆成点 \(i\) 和 \(i'\) ,且 \(i\) 和 \(i'\) 之间连一条容量为 \(h_i\) 的边
用 \(i\) 表示跳到了石柱 \(i\),\(i'\) 表示从 \(i\) 点开始跳向别的石柱
若是能从一个石柱 \(i\) 跳到另一个石柱 \(j\) ,那么就从 \(i'\) 向 \(j\) 连一条容量为 \(inf\) 的边
若是能从一个石柱 \(i\) 跳出边界,那么就从 \(i'\) 向 \(t\) 连一条容量为 \(inf\) 的边
我们可以假设最开始每只蜥蜴都不在石柱上,而是在源点 \(s\)
然后从 \(s\) 向每个蜥蜴初始位置 \(i\) 连一条容量为 \(1\) 的边,表示一只蜥蜴
这样就可以巧妙地解决这个问题
最大流 \(maxflow\) 表示的是最多有多少只蜥蜴能跳走
记录蜥蜴总数 \(sum\),跑一遍网络流,最终结果为 \(sum-maxflow\)
最小割
P4313 文理分科
题意:
有 \(n\times m\) 个人,每个人要么选文科,要么选理科
第 \(i\) 行 \(j\) 列的人选文科可以获得快乐值 \(art_{i,j}\),选理科可以获得快乐值 \(sci_{i,j}\)
若是一个人选的文科且上下左右的人都是文科,他可以获得额外快乐值 \(sameart_{i,j}\)
若是一个人选的理科且上下左右的人都是理科,他可以获得额外快乐值 \(samesci_{i,j}\)
求这些人的快乐值总和最大是多少
思路:
非 \(A\) 即 \(B\) ,典型的最小割
先不考虑额外快乐值
在集合 \(S\) 中表示选文科,在集合 \(T\) 中表示选理科
从 \(s\) 向点 \((i,j)\) 连容量为 \(art_{i,j}\) 的边,从点 \((i,j)\) 向 \(t\) 连容量为 \(sci_{i,j}\) 的边
这样求最小割,割掉最少不要的快乐值,剩下的就是答案
考虑额外快乐值
我们新建一个节点 \(x\) 对应点 \((i,j)\) 的文科额外快乐值,从 \(s\) 向点 \(x\) 连容量为 \(sameart_{i,j}\) 的边
考虑上下左右及自己都必须选文科,因此从 \(x\) 向 \((i,j)\),\((i-1,j)\),\((i+1,j)\),\((i,j-1)\),\((i,j+1)\) 都连一条容量为 \(inf\) 的边
显然这五条边是不会被割掉的
因此若是这五个点中有两个点不在一个集合内,就必须要断掉它们之间的联系,因为 \(x\) 把它们连在一起了
此时不能割容量为 \(inf\) 的边,就只能割容量为 \(sameart_{i,j}\) 的边
理科的同理,我们新建一个节点 \(y\) 对应点 \((i,j)\) 的理科额外快乐值,从 \(y\) 向点 \(t\) 连容量为 \(samesci_{i,j}\) 的边
从 \((i,j)\),\((i-1,j)\),\((i+1,j)\),\((i,j-1)\),\((i,j+1)\) 向 \(x\) 都连一条容量为 \(inf\) 的边
根据最小割=最大流
跑一边 \(dinic\) 得到最大流 \(maxflow\),最终的答案是 \(all\_happiness-maxflow\)
P2762 太空飞行计划问题
题意:
给定一张图,有左侧的点和右侧的点,左侧的点点权为正(对应试验),右侧的点点权为负(对应器材),如果选择了左侧的某个点就必须要选右边的一部分点。要求最大化点权和。
思路:
若是左侧的点需要右侧的点,则连一条从左侧的点向右侧的点的有向边,这样问题就转换为:
给定一个有向无环图,点有点权,选择一个子图,满足子图上如果选择了一个点就必须选择它后继的所有点。最大化点权和。
这是一个经典最小割问题,叫做最大权闭合子图问题
建图操作如下:
从 \(s\) 向所有正权值的点连一条权值为点权的边,从所有负权值的店向 \(t\) 连一条权值为点权绝对值的边
保留原图中所有的边且容量为正无穷
则原图中最大点权和为原图中正点权权值和减最小割
\(S\) 包含所有要的点,\(T\) 包含所有不要的点
最小割割去的边必然与 \(s\) 或 \(t\) 相邻,因为其他的边容量均为 \(inf\)
当我们选择要一个正权值点的时候,必然会将其放入集合 \(S\),这样就会割掉与其相连的负权值点与 \(t\) 的连边,这时候割去了需要减去的值
当我们选择不要一个正权值点的时候,必然会将其放入集合 \(T\),这样就会割掉其与 \(s\) 相连的边,这时候割去了需要减去的值
这样求得的割就是原图正点权和需要减去的部分,最小割就能减的最少,这样点权和最大
P3227 切糕
题意:
你在切一个蛋糕,蛋糕每个点有一个非负不和谐值 \(v\),切蛋糕的规则如下:
首先将每一个竖列的坐标用 \((x,y)\) 表示,数列上的点就是 \((x,y,z)\)
每次在每一数列选择一个点
对于数列 \((x,y)\) 我们选的点高度记作 \(f(x,y)\),那选的点坐标即为 \((x,y,f(x,y))\)
定义:竖列 \((x,y)\) 的相邻竖列坐标可表示为 \((x-1,y)\) \((x+1,y)\) \((x,y-1)\) \((x,y+1)\)
选点坐标时有一个限制:每一个竖列选的坐标 \((x,y)\) 与其相邻的竖列 \((a,b)\) 坐标高度差不超过 \(D\)
即 \(|f(x,y)-f(a,b)|\le D\)
现在求 \(\min\sum v[x][y][f(x,y)]\)
思路:
先去掉高度差不超过 \(D\) 的条件,那么这就变成了一个求最小割的题目
我们直接把每一个竖列的所有点依次相连,容量为 \(v\) ,且从 \(s\) 连一条到这列起点,容量为 \(inf\) 的边,从这列终点连一条到 \(t\),容量为 \(inf\) 的边
但是还有高度差不超过 \(D\) 的条件,所以考虑让建好的网络中即使割掉高度差超过 \(D\) 的地方也无影响
于是我们就只需要从 \((i,j,k)\) 向 \((i\pm 1,j,k-D)\) 和 \(i,j\pm 1,k-D\) 连一条容量为 \(inf\) 的边
会发现这样的话即使割掉所有不合法的边仍能从 \(s\) 走到 \(t\)
画图模拟一下就可以理解了
最后的结果就是最小割
P2805 植物大战僵尸
题意:
给定一个有向图,点有点权,选择一个子图,满足子图上如果选择了一个点就必须选择它之前的所有点。最大化点权和。
这里的之前所有点指从这个点出发,沿着反向边能跑到的所有点
思路:
这个题无非就是这个的变式,是一个最大权闭合子图问题
但是这道题需要除去环,所以用拓扑排序
若是拓扑排序的队列为空但某个点入度仍大于 \(0\),则此点在一个环内,应该除去
而且这道题边是反的,因此跑完拓扑排序后把边反过来,跑一边网络流就行
具体做法不再叙述
费用流
P1251 餐巾计划问题
题意:
一个餐厅在相继的 \(N\) 天里,每天需用的餐巾数不尽相同。
假设第 \(i\) 天需要 \(r_i\)块餐巾( \(i=1\sim N\))。餐厅可以购买新的餐巾,每块餐巾的费用为 \(p\) 分;或者把旧餐巾送到快洗部,洗一块需 \(m\) 天,其费用为 \(f\) 分,或者送到慢洗部,洗一块需 \(n\) 天(\(n>m\)),其费用为 \(s\) 分(\(s<f\))。
每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
试设计一个算法为餐厅合理地安排好 \(N\) 天中餐巾使用计划,使总的花费最小。
思路:
每一天要处理两件事:准备干净餐巾以及处理脏餐巾
因此考虑把每个点拆成两个:早上和晚上,早上准备干净餐巾,晚上处理脏餐巾
建立一个源点 \(s\) 和一个汇点 \(t\)
- 从 \(s\) 向第 \(i\) 天早上连一条容量为 \(inf\),费用为 \(p\) 的边,表示每一天可以购买任意多餐巾
- 从第 \(i\) 天早上向汇点连一条容量为 \(r_i\),费用为 \(0\) 的边,表示第 \(i\) 天早上需要准备 \(r_i\) 的餐巾
- 从源点向第 \(i\) 天晚上连一条容量为 \(r_i\),费用为 \(0\) 的边,表示第 \(i\) 天需要处理的脏餐巾数量
- 从第 \(i\) 天晚上向第 \(i+1\) 天晚上连一条容量为 \(inf\),费用为 \(0\) 的边,表示第 \(i\) 天的脏餐巾留到第 \(i+1\) 天
- 从第 \(i\) 天晚上向第 \(i+m\) 天早上连一条容量为 \(inf\),费用为 \(f\) 的边,表示快洗第 \(i\) 天的脏餐巾
- 从第 \(i\) 天晚上向第 \(i+n\) 天早上连一条容量为 \(inf\),费用为 \(s\) 的边,表示慢洗第 \(i\) 天的脏餐巾
这样就做完了
P2153 晨跑
题意:
有 \(n\) 个点,\(m\) 条边,起点为 \(1\),终点为 \(n\),每个边都有边权
求 \(1\sim n\) 最长有几条的路线(满足每次经过的点都不相同),且在这个情况下最少需要跑的路程是多少
思路:
这不是最小费用最大流吗?
把原路线容量设为 \(1\) ,费用设为边权就可以求解
但是要满足每次经过的点都不相同
考虑拆点
把点 \(i\) 拆成 \(i\) 和 \(i+n\),从 \(i\) 向 \(i+n\) 连一条容量为 \(1\) 费用为 \(0\) 的边
这样就行了
答案分别是最大流和最小费用
P2469 星际竞速
题意:
给一张 DAG,边有边权
你最开始不在图内
你可以耗费 \(a_i\) 的代价直接到达 \(i\) 点,也可以消耗 \(edge_{x\rightarrow y}\) 的代价从 \(x\) 走到 \(y\)
求使所有点都被走到的最小代价
思路:
我们可以换一种理解方式:
每次都不在图内,然后瞬移到某一点 \(x\) ,然后再走
考虑费用流,让你在最大流的时候把每个点都遍历一遍,然后同时求出最小代价
从 \(s\) 点开始表示出发,走到 \(t\) 点表示结束
因此我们可以把所有边容量设为 \(1\),这样无论如何最大流的结果都不会变
若是你想在 \(x\) 点结束,你必定是位移到 \(x\) 或从某处走到 \(x\)
考虑拆点
我们把 \(i\) 点 拆成 \(i\) 和 \(i'\) ,然后从 \(s\) 向 \(i'\) 连费用为 \(a_i\) 的边,\(i'\) 向 \(t\) 连费用为 \(0\) 的边,\(s\) 向 \(i\) 连费用为 \(0\) 的边
若存在边 \(edge(i,j)\) \(i<j\),则从 \(i\) 向 \(j'\) 连费用为 \(edge(i,j)\) 的边
这样的话对于每一个点 \(i\) 对应的 \(i'\) 都会走向 \(t\) ,并且必定会由 \(s\) 或前面的点走到,可以更新最小答案
所以这种做法正确,最小费用即为答案
标签:费用,容量,石柱,练习,餐巾,网络,蜥蜴,inf 来源: https://www.cnblogs.com/into-qwq/p/16455752.html