zoukankan      html  css  js  c++  java
  • 「总结」网络流

    网络流专题,总结一下。

    一、最大流

    一个网络图的最大流量,满足网络流的各种性质的情况下。

    1.蜥蜴

    简单的拆点,在点之间限流即可,设有$a_i$的高度,从$S$向有蜥蜴的柱子$x$连边,边缘的柱子向$T$连边,距离小于$i,j$。

    $$link(S,x,1),link(i_0,i_1,a_i),link(j,T,INF),link(i,j,INF)$$

    跑最大流就可以了。

    2.星际战争

    直接二分答案mid,设$i$为武器,$j$为机器人。

    连边:

    $$link(S,i,mid),link(i,j,B_i),link(j,T,A_j)$$

    那么直接$check$是否满流即可。

    要打小数网络流。

    3.网络吞吐量

    $SPFA$一下然后求出最短路$DAG$,每个点限流直接跑最大流即可。

    4.士兵占领

    典型的行列建边,先判不合法,然后跑最大流,看看能够让行列尽多重叠多少个,剪掉这些就是答案了。

    5.紧急疏散evacuate

    二分答案mid。

    对于每个门拆出$mid$个点。

    然后从上一个时间链接到下一个时间,跑最大流判断是否为人数即可。

    细节很多。

    优化复杂度可以考虑枚举答案。

    在原本的门上添加一条新边来,接着跑$Dinic$,然后再判断满流。

    时间复杂度更加优秀。

    二、最小割

    1.狼抓兔子

    一看就可以看出来是最小割的板子。

    建图直接跑即可。

    但是复杂度不对。

    发现是平面图最小割。

    建立对偶图,将整个图翻转90度并且把空白区域变成点即可。

    直接最短路。

    2.切糕

    仍然是最小割。

    对于每个高度的点开一个点,用一条链穿在一起。

    这样直接跑最小割就是不考虑高度限制情况下的最优解。

    如果加上高度限制就可以简单的用$INF$边$link(id[i][j][k],id[i+1][j][k-D],INF)$

    这样再跑就可以了。

    3.海拔

    首先保留整数,可以看出每个点虽然表面上是小数海拔,但对于结果来说只有$0/1$两种情况。

    而且这两种情况必然是将整张图的十字路口严格分为两个部分,这些部分之间的点必须要从$0->1$的海拔。

    所以相当于在求最小割了。

    当然用最大权闭合子图一样可以做,但是复杂度要高而且得到的答案必然是分开了的两个部分。

    时间不对只能$T90$

    仍然是对偶图,直接$dijk$即可。

    4.不同的最小割

    最小割树的板子。

    对于三个点来说,他们之间的最小割最多只有两种情况,扩展到$n$个点的话,最多只有$n-1$种情况。

    那么考虑分治算法。

    首先在图中随意取两个点$x,y$跑最小割,得到割$w$,分开$S$和$T$集合,那么这时$S$中的任何一个点到$T$中的任何一个点的最小割都要小于等于$w$,否则割不掉,建一条树边$x->y|w$。

    这样对于$S$和$T$递归的进行这个过程。

    最后两个点之间的树上路径的$min$就是两个点之间的最小割。

    直接$n^2$统计即可。

    5.老C的方块

    类似切糕的思路,不过更加繁琐一些。

    四种颜色染色,使得每条不合法状态都是通过红->蓝->绿->黄。

    这样直接按照红->蓝->绿->黄的方式建边,然后跑最小割即可。

    三、最大权闭合子图

    根据最小割的模型,我们建立另外一个模型,关于物品是否被选择的模型。

    对于一个物品来说,选择存在某种收益。如果这个收益是正值,我们建边$S->i|a_i$,并在答案中累加$a_i$,如果是负权则不累加并连边$i->T|a_i$。

    具体来说大概长这样:

    如果一个物品在一种方案中被选择我们就隔断他链接$S$的边,否则是$T$的。

    当然了,$S$和$T$可以根据不同的需要调换位置。

    1.最大获利

    对于每一个请求拆出一个点来。

    对于每个询问$p$来说建图为:

    $$link(S,p,c_p),link(p,A_p,INF),link(p,B_p,INF),link(A_p,T,w_{A_p}),link(B_p,T,w_{B_p})$$

    也就是利用了$INF$边不可割断的特性,强制选择两方面之一。

    2.$happiness$

    对于每两个人的关系拆出两个点来。

    设两个点分别为$i,j$,拆出两个点为$l,r$,他们单独选文/理的贡献是$a_i/b_i$,共同选文/理的贡献是$c_{i,j},d_{i,j}$

    这样规定割$S$这边代表选文,割$T$代表选理。

    那么这样建图:

    $$link(S,i,b_i),link(S,j,b_j),link(i,T,a_i),link(j,T,a_j),link(S,l,d_{i,j}),link(r,T,c_{i,j})$$

    这样相当于规定了每种情况的贡献,紧接着体现这些情况间的关系。

    $$link(l,i,INF),link(l,j,INF),link(i,r,INF),link(j,r,INF)$$

    这样就强制了四种情况对于两个人之间关系的处理方式。

    两个都选文的情况下,必须要割掉$S->l$这样就去除了两个人都选理的贡献,反之则需要割掉$r->T$,这样就去掉了两个人都选文的贡献。

    一个选文一个选理的情况下,由于$INF$边的强制要求,这两条边都必须要割掉,那么就把他们都割掉,这样也是对的。因为两个人之间的贡献一个也不能有。

    这道题最难的地方在于综合利用拆点技术和$INF$边来共同体现每种情况之间的联系,从而达到各个情况的取值的正确。

    3.$employ$人员雇佣

    设一对人员关系为 $i,j$,我们发现,如果两个人都被雇佣,才能收到额外收益,否则不仅拿不到额外收益,而且还要减掉一定的额外收益。

    我们设一个人的权值$w_i=sumlimits_{k=1}^{n}E_{i,k}$代表他所能给其他人带来的贡献。

    那么这样建图:

    $$link(S,i,a_i),link(S,j,a_j),link(i,T,w_i),link(j,T,w_j)$$

    这样规定每个点的权值,割$S$代表雇佣,割$T$代表不雇用。

    可以发现这样是对的,然后体现两个人之间的关系,由于当一个人选一个人不选的情况下,会造成额外的负担,那么接着建边。

    $$link(i,j,2*E_{i,j}),link(j,i,2*E{j,i})$$

    乘二的原因是由于本来的那部分贡献拿不到,还会造成同样大小的影响。

    这样当一个人选一个人不选的时候,就必然要割掉$i,j$间的一条边,从而体现$i,j$之间的互相影响这一条规定。

    这道题的难点在于区分统计两个人之间的关系和自身属性,另外还有模型转化方面。

    4.线性代数

    看起来让人一脸懵,查了查什么是矩阵转置才会做,难点在题意转化上面,$A$是$0/1$矩阵,可以看到最大权闭合子图的影子。

    设$G=AB$发现$G$的本质就是,对于$B$的每一行都按照$A$的$0/1$情况来累加到$G$的对应位置上。

    原本的矩阵乘法是$A$的行乘上$B$的列,那我们这样区分计算贡献,就变成了上面那种情况。

    还要减掉一个$C$,然后在乘上$A^T$。

    区分两部分计算。

    $(AB-C)A^T=ABA^T-CA^T$

    发现左边的部分的贡献其实就是行列向量相乘,而且还是$0/1$的形式。

    这样就方便的转化这一部分的贡献,对于$B$上面的每一个位置$B_{i,j}$,我们规定在$A$上的两个位置$A_i,A_j$均为$1$的时候我们才可以拿到这部分贡献。

    在看看后面的部分,当$A_i$是1的时候,我们要付出$C_i$的代价。

    设$w_i=sumlimits_{k=1}^{n}B_{i,k}$

    那么这样建图:

    $$link(S,i,w_i),link(S,j,w_j),link(i,T,C_i),link(j,T,C_j)$$

    那么$S$边视为选0,$T$边视为选$1$。权值固定了,着手关系体现。

    $$link(i,j,B_{i,j}),link(j,i,B_{j,i})$$

    这样如果是一个为0一个为1的情况我们必然要割掉一条边,这样符合两个都选才能获得贡献的规定,而如果都选或者都不选,都不会割掉这两条边,单用第一层建图的方式仍然是正确的。

    难点在于题意转化,将矩阵乘法关系转化为布尔运算关系,转化完了和人员雇佣几乎一样了,破题想了一天。。结果还是我线性代数太差了的缘故。

    5.植物大战僵尸

    相对于之前的几道题还是要简单一点。毕竟是十年前的题了。

    学长讲过一次,没怎么听懂。

    其实就是一些限制关系,如果一个点没有被破坏,那么另外一个受他控制的点也不能被破坏。

    那么如果两个点$i,j$之间存在控制关系,建立$i-->j|INF$的边。对于必须从右往左破坏的限制,我们从左边的点向它临接的右边的点建立$INF$边

    首先来一次$INF$边的$topsort$去掉环上的点。

    这些点的贡献不可能被计算。

    对于一个正权点:$link(S,i,a_i)$

    否则:$link(i,T,-a_i)$

    这样联通$INF$一起跑网络流就可以了。

    难点在于去掉那些环上的点,可以发现不去掉根本做不了。

    6.寿司餐厅

    前天晚上睡不着想了一晚上就会了。

    其实不是特别简单的一道题了,可以说我刷的里面的难度巅峰了。

    不过很庆幸还是想出来了。

    一开始想的是能否和人员雇佣一样,将子区间的贡献累加成大区间的权值,直到我想明白了一个性质。

    对于一个区间来说,如果某种方案选择了这个区间,那么在强制选择这个区间的方案中最优秀的那些方案比然不会选择其子区间。

    很好理解,可能出现正贡献的只有那些$d_{i,j}$,而如果选择了一个区间之后,可以发现再选择其子区间只能出现负贡献而不会出现正贡献。

    那么这种选择就是不优的。

    这样就可以简单了。

    因为子区间不会被选择的性质,我们发现一个位置寿司最多被吃一次。

    那么对于每一种寿司都建立一个新点,从代表最小的区间$[i,i]$的点向他们连$INF$边,这样可以保证如果某一个点是选择的(从$S$来的边没有被隔断),必然有一条流是通过$INF$的,我们再从这个新点向$T$连边,边权为$ma_i^2$,这样就可以体现代价中的一部分,注意到代价有另外一部分,跟每种寿司被吃的个数有关,这种贡献从最小区间代表的点链接向$T$即可,这样每次选择一个点,我们必须吃他连接向$T$的点,这样边权设置为$a_i$即可,保证吃一次就做编号大小的贡献。

    我们不再像人员雇佣那样将一个人的贡献全部都累加到一起,因为我们发现因为区间的记忆性质,是不可能以一个区间的选择有无来判断其子区间是否做贡献。

    那么这个区间的权值就定为他自身的综合美味度,由于其子区间不可能再次被选,可以认为选择了一个大区间就要强制其子区间被选择,那么从一个大区间向子区间连$INF$边即可。

    可是这样建图是$1e8$级别的边数。

    考虑到一个点如果控制子区间的子区间,其实只需要控制其子区间即可。那么直接从一个点向比他长度小1的子区间连边即可,边就是二叉树$O(n)$级别的了。

    这个题很难。难点很多,主要在于性质的发现和边数的优化方面。

    四、费用流

    1.晨跑

    那么每个点拆点限流。

    然后直接按照给出的图建边。

    跑最小费用最大流即可。

    2.修车

    既然说是平均等待时间最小那么也就是总和最小了。

    老套路按照时间拆师傅。

    然后链接源汇费用为0,流量为1。

    他是倒数第$k$个时间修的,就会给后面修的人带来$k*w_{i,j}$的代价

    那么连边跑最小费用最大流即可。

    3.数字配对

    首先发现性质。

    每个可以配对的数字,他们必然是质因子个数相差$1$的。

    直接奇偶二分图。

    然后源汇限流跑最大费用可行流即可。

    4.美食节

    卡常题,T了33次。

    首先这题基本和修车一样就不赘述建边了。

    然后我们发现了$EK$的小性质。

    每次只有一条增广路。

    那么我们可以不直接建出全部的点和边,而是流满当前时间的边之后再新建一条新时间的边。

    这样就可以痛苦$AC$了。

    5.无限之环

    首先发现每条边的流量必然是相邻两个点流过去。

    老套路黑白染色。

    然后对于每个相对的黑色接口$i$和白色接口$j$,(前提是有这个接口)

    $link(S,i,1,0),link(i,j,1,0),link(j,T,1,0)$

    对于不同的水管,考虑不同的链接方式。

    转90度是费用为1,转180度是费用为2。

    这样连接即可。

    6.星际竞速

    比较神仙的一个题。

    一开始想了个不太妙的思路,这样不能强制跑满流,当时不会上下界,不然我估计直接上下界暴力也可以。

    还是考虑费用流。

    如果每次传送的时间是$G$的话。

    我们对于每个点都拆点。但不链接拆的两个点。

    这两个点分别代表的意思是,在进入这个点的状态,和可以从这个点出发的状态。

    让他们分别链接$S,T$

    $$link(S,id[i][0],1,0),link(id[i][1],T,1,0),link(S,id[i][1],G)$$

    然后连接每个点之间的连边即可。

    $$link(id[i][0],id[j][1],1,w)$$

    跑最小费用最大流。

    7.志愿者招募

    真的是大神大神题。

    完美结合了费用流和线性规划。(其实网络流就是线性规划吧?)

    我们设一种人的人数为$d_i$,可以覆盖某一天的人的集合为$S_i$

    那么:

    $$a_i>=sumlimits_{jin S_i}d_j$$

    设辅助变量$r_i$

    使得:

    $$a_i=-r_i+sumlimits_{jin S_i}d_j$$

    可以列出$n$个方程。

    让这些方程上下相减。

    得到$n+1$个方程(算上$n+1$和0)

    形如$$a_{i+1}-a_i=r_i-r_{i+1}+sumlimits_{jin S_{i+1}}d_j-sumlimits_{jin S_{i}}d_j$$

    这个可以说是类似流量守恒的东西。

    流入和流出相等。

    我们把负项放到左边,正项放到右边。

    而且这个时候每一项最多出现了两次。

    因为差分的缘故,只会出现$S_i$,$T_{i+1}$两个地方。

    然后对于每个$r$。如果正项在第$i$个式子,负在$j$,那么$link(i,j,INF,0)$

    然后对于每个$d_k$。如果正项在第$i$个式子,负在$j$,那么$link(i,j,INF,w_k)$

    如果常数是正数就从源点连过来,否则连向汇点。

    五、上下界网络流

    1.80人环游世界

    限定了每个点的流量,其实就是上界和下界一样大的意思了。

    然后从原点连向每个点,同时再链接点和点之间的边,费用为边权,每个点拆点上下界限流。

    然后都要流向汇点。

    建立超源超汇补流。

    跑一个最小费用可行流即可。

    2.矩阵

    看到最小的最大值,直接二分答案。

    然后老套路行列二分图建边,对于每个点连上下界为$[L,R]$的边。

    对于二分的答案$mid$,发现了行列间的性质是:

    $$a_i-mid<=sumlimits_{j=1}^{n}B_{i,j}<=a_i+mid$$

    这样建上下界$[a_i-mid,a_i+mid]$。

    最后$check$判断一下是否满流即可。

    3.支线剧情

    要求每条边必须至少走一次。

    按照要求建边,也就是上下界为$[1,INF]$。

    然后源汇补流,跑最小费用可行流即可。

    4.旅行时的困惑

    看似是个树,然后要求反向边建立,同时使得各个边被覆盖一次。这是题意转化。

    那么仍然建立源汇,分别链接反向图上入度为0和出度为0的点。

    然后上下接和支线剧情一样。

    这次跑最小流。

    5.清理雪道

    和旅行时的困惑一样。也是要求每条边至少走一次。

    不过这次要简单的多,不需要转化题意。

    是裸的最小流。

    网络流暂时这么多。

  • 相关阅读:
    分享一个js方法
    微信小程序中如何使用setData修改数组或对象中的某一参数
    微信小程序实现图片上传功能
    微信小程序图片上传放大预览删除代码
    小程序单张图片 和 九宫格图片上传、预览、删除示例
    微信小程序多图上传/朋友圈传图效果【附完整源码】
    shell 和awk性能对比
    超实用的8个Linux命令行性能监测工具
    storm分组模式
    Python程序的执行原理(转)
  • 原文地址:https://www.cnblogs.com/Lrefrain/p/11960278.html
Copyright © 2011-2022 走看看