• 网络流初探


    简记一下最近做的网络流,大概都是我不会的

    可能也是一些经典的模型吧,可以翻看回味一下...

    P1231 教辅的组成

    大意:有一些书,练习册,答案。现在知道书和练习册以及书和答案的对应关系,一本书,一本相应练习册,一本相应答案可以配套成一本集。问现在最多配套出多少套?

    很经典的拆点,虽然不难但是很有教育意义。我们将书拆点,中间连权值为 \(1\) 的边,然后直接按照对应关系连一下边就行了。

    P2754 [CTSC1999]家园 / 星际转移问题

    大意:有一些不同的飞船在地球和月球之间按照某种循环顺序往返于地球月球和空间站之间,每个飞船有一个载人最大值。问最少需要多少天把所有人送到月球上?

    也是一道很经典的枚举答案的题。首先我们会发现这个题每天的转移会很不一样,因此我们就难以求出最小的天数,不妨枚举这个天数。首先建立两个点分别表示地球和月球,接着,对于每一天,我们新建 \(n\) 个点表示当天的 \(n\) 个转移站,再从上一天连边过来其实就可以转移了。

    P2762 太空飞行计划问题

    大意:有一些实验和实验仪器,每个实验需要一些实验仪器。完成一个实验能获得一些收益,使用仪器会花费一定金额,仪器可以重复使用,问最大收益是多少?

    最大权闭合子图模板。首先我们直接求解问题需要我们找到匹配关系,而且相关的点不能再用,这样很复杂。我们不妨反过来想,如果我们考虑不选择那些仪器和实验不就能知道得到的利润了。于是我们发现哪些点不选是类似于割边的过程,于是我们可以考虑求某个图的割的值。于是我们建立超级源点,汇点 \(S,T\),从 \(S\) 向每个实验连一条权值为该实验利润的边,接着从每个实验仪器连向 \(T\) 一条权值为该实验仪器费用的边,最后再从实验连向相对应的实验仪器一条权值为 \(inf\) 的边。事实上我们发现,这张图首先不会切掉中间权值为 \(inf\) 的边,于是这样就很好地实现了我们上面的不选点花费的代价。进一步我们会发现,如果我们割走一条 \(S \rightarrow x\) 的边,那么我们 \(x\) 所对应实验仪器的边可以被保留,这就等价于不选实验 \(x\)。相反地,如果 \(S \rightarrow x\) 的边没有被割掉,则 \(x\) 所对应实验的边都要被割掉,这就等价于选择实验 \(x\)。于是问题就转化为求所有权值和 \(-\) 最小割了。

    P2774 方格取数问题

    大意:给你一张网格图,每个点有点权,可以取一些点的点权,相邻的点不可以同时取,问取得的最大值为多少?

    又是一道简单题。其实记这道题的目的是为了探究最大权闭合子图的应用模型。其实,我们会发现一个闭权子图实际上就是一种依赖关系,即对于任意一条边 \(u \rightarrow v\) 选择了 \(u\) 就必须选择 \(v\)。那么我们建立超级源点汇点 \(S, T\),从 \(S\) 向每个正权点连一条权值为正权点权值的边,从负权点向 \(T\) 连一条权值为相反数的边,再按照所有给出的边连上权值为 \(inf\) 的边,这样所有权值的绝对值 \(-\) 最小割即为最大权闭合子图。实际上很多问题不会直接存在依赖关系,往往存在的是某种互相抵制的关系,例如对于边 \(u \rightarrow v\) 选择了 \(u\) 就不能选择 \(v\)。这又怎么办呢?我们再反过来想,将不选择 \(v\) 看做是在总权值中减去 \(v\) 的权值,哪这个时候的 \(v\) 是不是就相当于上面的负权点呢?这何尝又不是一种新的依赖关系呢?本题就是一个很好的体现。

    下面是几个二分图著名定理

    • 二分图最小点覆盖 \(=\) 最大匹配数

    • \(DAG\) 最小路径覆盖 = 总点数 - 最大匹配数

    • 二分图最大独立集 \(=\) 总数 \(-\) 最小覆盖集

    其实还有几个不太常用的,先咕一下...

    P2469 [SDOI2010]星际竞速

    大意:求\(DAG\) 带权最小路径覆盖。

    在像这样已经出现过有类似问题的问题,我们为什么不可以从类似的问题的做法出发,进一步改进这个做法呢?这个题也是这样。或者说,如果我们没有见过 \(DAG\) 最小路径覆盖,我们为什么又不可以从最简单的情况不带权思考呢?另外,很多网络流尤其是二分图可以反过来思考,甚至运用反证法,如果不对,会出现怎样的情况呢?

    P3163 [CQOI2014]危桥

    大意:给你一张无向图,有些边只可以通过两次,其他边可以无限走。现在问你能否 \(a_1, a_2\) 之间往返 \(a_n\) 次同时 \(b_1, b_2\) 之间往返 \(b_n\) 次。

    很好的一道题。首先我们一般会想到按照图直接连边,实际上无向图来回一趟可以直接看作从 \(S\)\(T\) 的一条路径。这样按照题目给的危桥边权为 \(1\) 其他为 \(inf\) 跑最大流,最后判断一下流量。但是这样会有点问题,可能 \(a\) 的流量会跑到 \(b\) 去,事实上这是不合法的。这里有一个常用的图论的技巧,就是判断合法性可以尝试交换起点终点再跑。这个套路可以了解一下...

    P1361 小M的作物

    大意:将一个物体选入集合 \(A\) 能获得 \(a_i\) 的收益,选入集合 \(B\) 能获得 \(b_i\) 的收益。有一些两种物体同时选入 \(A\) 集合能获得 \(c_i\) 的收益,同时选入集合 \(B\) 能获得 \(d_i\) 的收益,问最大收益是多少?

    也是很好的一道题。同样的,正着做不好做考虑反过来去掉一些收益(事实上尤其是这种只有两个选择的情况一定要想到最小割分割在两个集合中)。我们考虑将每个点 \(i\)\(S\)\(i\) 连一条边权为 \(a_i\) 的边,从 \(i\)\(T\) 连一条边权为 \(b_i\) 的边。那么对于每一个 \(i\) 我们需要选择切掉其中的一条边分到两边的某个集合中(注意最小割的本质就是将点分到两个集合中)。接下来考虑额外收益,因为我们需要考虑最小割,于是要把收益放在边权上体现,但是我们总不好直接在原图上连边吧,这样相当于无中生有。自然地,我们考虑新建点 \(x\) 假设两个点 \(a, b\) 同属于 \(A\) 集合能获得收益 \(c\)。我们如何思考?因为我们所要转化的是割掉某条边的体现,于是我们考虑割掉收益 \(c\) 这条边的条件,不难发现即 \(a, b\) 中至少有一个没有割去与 \(T\) 的连边。为了让这张图继续不连通,我们一定要构造一条从 \(S \rightarrow x \rightarrow a / b \rightarrow T\) 的一条路径,这样才能顺利割走 \(c\)。于是我们从 \(S\)\(x\) 连一条边,\(x\)\(a, b\) 连一条边。为了让 \(c\) 只减去一次,\(S\)\(x\) 的边权我们设为 \(c\),其他两条边权设为 \(inf\)(不能割去)即可。同属于集合 \(B\) 类似。

    很好的一道题啊!被反复出了好几次,类似的有P1646 [国家集训队]happiness,P4313 文理分科,其实这几题一毛一样

    P3227 [HNOI2013]切糕

    大意:对于平面上每个整点 \((x, y) (1 \le x \le P, 1 \le y \le Q)\) 需要选择一个高度 \(f(x, y) = z (1 \le z \le R)\),将花费 \(V[x][y][z]\) 的代价。且对于平面上相邻的点 \((x', y')\) 要求 \(\left| f(x, y) - f(x', y') \right| \le D\)。求最小代价。

    不难想到最小割。因为我们对于每个整点 \((x, y)\) 只需要选择一个高度即可,于是我们可以考虑将每一个整点拆成 \(R + 1\) 个点,从 \(S\)\((x, y, 1)\) 连一条权值为 \(inf\) 的边,从 \((x, y, i)\)\((x, y, i + 1)\) 连一条权值为 \(V[x][y][i]\) 的边,最后从 \((x, y, R + 1)\)\(T\) 连一条边权为 \(inf\) 的边,利用这种类似串联的方法我们很好地解决了只割一条边的要求。接下来就要考虑后面那个条件了。我们这样想,为了不去割不合法的边,我们可以让割不合法的边依然让图联通即可,也就是存在一条通路。另外,因为对称性,对于一个点 \((x, y)\) 和相邻的一个点 \((x', y')\) 只需考虑 \(f(x, y) - f(x', y')\le D\)的情况不合法。加入我们当前选择的是 \((x, y, z) (z \ge D + 1)\) 那么不合法的边是 \((x', y', z') (z' < z - D)\) 于是我们从 \((x, y, z)\)\((x', y', z - D)\) 连一条为 \(inf\) 的边就好了。

    P2053 [SCOI2007]修车

    大意:有 \(n\) 辆车,\(m\) 个人,第 \(i\) 辆车第 \(j\) 个人修花费 \(T_{i, j}\) 的时间。问所有车主等待的平均时间最小为多少?

    首先不难想到将求平均值最小转化为求总体等待时间最小。接下来我们发现我们像二分图那样套路连边显然是不能计算出总体等待时间的,因为我们不能知道这个车之前修了那些车。那么顺着这个思路,我们不难发现我们实际上需要解决的问题是怎样知道之前修了那些车。事实上我们不好直接将前面的时间累加起来,这样的话我们尝试考虑每辆车对总时间的贡献。假设第 \(j\) 个人选择修了 \(a_1, a_2, ..., a_k\) 这些车,那么总时间花费 \(T = a_1 + a_1 + a_2 + a_1 + ... + a_1 + a_2 + ... + a_k = a_1 * k + a_2 * (k - 1) + ... + a_k\).自然地我们就可以将每个人拆成 \(n\) 个点,第 \(i\) 个点表示当前人在倒数第 \(i\) 个修车的花费。那我们从超级源点 \(S\)向第 \(i\) 个车连一条流量为 \(1\) 花费为 \(0\)的边,从第 \(i\) 个车向第 \(j\) 个人的第 \(k\) 个点连一条流量为 \(1\) 花费为 \(k * T_{i, j}\) 的边,从第 \(i\) 个人第 \(j\) 个点连一条流量为 \(1\) 花费为 \(0\) 的边跑最小费用最大流就好了。

    接着我们看另一道题P2050 [NOI2012]美食节,题面跟刚刚的题一样,就是数据范围扩大了。不难发现,在上面那个题中拆出来有用的点实际上只有 \(n\) 个点有用,很多的点是没有用的。实际上在拆出来的点中越靠前的点的代价就越小因此我们在跑最小费用最大流的时候一定是从最前面的点开始流走流量的,因此,我们只需要首先把所有人割成一个点,在那些流走流量的点后面新建一个点继续一直跑就行了。这样的话点数就是线性级别了的。

    P3980 [NOI2008]志愿者招募

    大意:一共有 \(n\) 天,第 \(i\) 天最少需要 \(a_i\) 个志愿者工作,一共有 \(m\) 种志愿者可以招募,第 \(i\) 种志愿者可以从 \(s_i\) 工作到 \(t_i\) 每人需要 \(c_i\) 的花费。现在要求满足每天最少需要的志愿者情况下的花费最小。

    同样的,我们如果使用二分图套路连边,那么每次的流量可能不会流到同一天去,因此我们需要换一种方法思考。不难想到使用最小费用最大流来解决这个问题,于是乎我们的目标就是需要建立一张能满足每条边增加的流量之和为 \(\sum{a_i}\) 且能满足要求的图。首先每天建立一个点是显然需要的,实际上我们上述的问题在于不能同时覆盖这整个区域,于是我们猜想可不可以每一种志愿者 \((s_i, t_i, c_i)\)\(s_i\)\(t_i\) 连一条流量为 \(inf\) 花费为 \(c_i\) 的边表示覆盖这整个区域呢?(实际上就是用这条边代替中间的这个区间)回过头来看,我们需要每条边增加的流量之和为 \(\sum{a_i}\) 不难想到从 \(S\)\(1\) 连一条流量为 \(0\) 费用为 \(0\) 的边,从第 \(i\) 个点向 \(i + 1\) 个点连一条流量为 \(-a_i\) 花费为 \(0\) 的边,从 \(n + 1\)\(T\) 连一条流量为 \(0\) 花费为 \(0\) 的边,这样最后跑出来最大流 \(0\) 就一定可以满足上面的要求。再去看那个猜想,我们惊奇地发现这个做法刚好可行,为什么呢?因为中间的边显然不能继续流走流量,那么就只有可能从上面的覆盖边流走流量,为了使最后的最大流为 \(0\) 则一定会将整个区间覆盖满,否则最大流将不会为 \(0\)。注意的是网络流负流量是搞不了的,于是我们只需要将所有边权整体加上 \(inf\),最后跑最小费用最大流是最大流为 \(inf\) 就是答案了。

    P3358 最长k可重区间集问题

    大意:你有一些开区间可以选择,现在需要保证数轴上的每个点被覆盖的次数不超过 \(k\) 次,求出最大的覆盖总长度。

    这个题是不是和上面那题很像,都是选择某个东西能覆盖一个区间的类型。回想一下上面那个题的做法,我们为什么要使用负流量呢?原因在于我们需要最大流为 \(0\) 的话则需要将这个区间内的最大值跑满,而这道题是要求不能超过 \(k\) 次,也就是意味着我们最多将最小值跑满,不难想到将上面那个题的 \(s_i\)\(t_i\) 的边流量改为正数就可以满足要求了。实际上这类题都是选择某个东西能覆盖一个区间的类型,可以从中理解到一种模型。

    P1251 餐巾计划问题

    大意:每天需要 \(r_i\) 个毛巾,你可以在每一天购进毛巾,每条费用为 \(p\);也可以将用过的毛巾送到快洗部,需要 \(m\) 天完成清洗,每条花费为 \(f\);可以送到慢洗部,需要 \(n\) 天完成清洗,每条费用为 \(s\);你也可以将脏毛巾留下来以后洗。现在为满足每天需要的毛巾数量下最少花费多少?

    网络流24题里面应该是很好的题了。首先,不难发现每天有两种状态,一种是可以使用的新毛巾,一种是已经使用的旧毛巾,为了方便流量的转移,我们将每天拆做两个点:分别表示每天的新毛巾和旧毛巾。那么旧毛巾就可以直接向后面的新毛巾连上对应的边了(即慢洗和快洗),接下来屯脏毛巾就直接由当前脏毛巾向后面脏毛巾连边就好了。现在我们知道了中间转移流量的方法,但是初始流量怎么来呢?不难发现,每天脏毛巾的初始量是一定的即 \(r_i\),所以从 \(S\) 向每天脏毛巾连一条流量为 \(r_i\) 费用为 \(0\) 的边就可以了,但是每天干净毛巾和买毛巾怎么解决呢?于是乎很自然地从 \(S\) 向每天干净毛巾连一条流量为 \(inf\) 费用为 \(p\) 的边就行了,接着再从干净毛巾连向 \(T\) 一条流量为 \(r_i\) 费用为 \(0\) 的边就好了,最后跑最小费用最大流。

    实际上这个题很类似于一种 \(dp\),我们只是用流量代替了 \(dp\) 中的状态,所以如果有时候 \(dp\) 不行了可以往网络流想想,很多线性规划问题都可以用费用流解决。实际上这里为什么我们要拆点,是因为转移方法太多而且有很多种状态,于是我们可以依据状态拆点或者是转移方法拆点。

    • 于2020.3.23日做完了网络流24题,好开心/cy
  • 相关阅读:
    一个方法只做一件事
    日常-生活-学习-经验分享
    Python 用下划线作为变量前缀和后缀指定特殊变量
    浏览器渲染的基本原理
    七个对我最好的职业建议
    web性能优化
    Javascript 设计模式
    数据结构与算法 Javascript描述
    mysql计算连续天数,mysql连续登录天数,连续天数统计
    Oracle计算连续天数,计算连续时间,Oracle连续天数统计
  • 原文地址:https://www.cnblogs.com/Go7338395/p/13270385.html
Copyright © 2020-2023  润新知