网络流与二分图 学习笔记
初三了还不知道网络流是啥就比较摸鱼了吧——csy
其实大概去年(也许这篇公开的时候就是前年了)这个时候 hb 就给我们都讲过这个东西了。然后 yxh tzc ymx 等一车人都学会了,就我鸽在那儿一直没学。然后这次是被 hb 强迫来学的,给了一堆东西(
u1s1 xht 的博客真香
(是个长篇大论,终于轮到我用一级标题了啊)
upd. 2021.1.7:终究还是鸽到了 2021 啊……网络流这玩意学了我整整 10 天,知识晶体都快从脑子里析出了。希望以后学的算法们都没这么难理解吧。
网络流
一个网络是一张有向图 ,其中有两个特殊的互异的点:源点和汇点 ,其中源点不能有流入,汇点不能有流出。该网络上可以定义边上的流函数 ,其中 。一个流函数 是一个可行流当且仅当:
- 容量限制:对于每组 都给定了一个容量函数值 ,需要满足 ;
- 斜对称:,可以理解为流出量等于流入量的相反数;
- 流量守恒: 都有
(这和 rzr 给我科普的流体连续性方程有点类似)。
根据斜对称和流量守恒,显然有 ,这个值是该流函数下该网络的流量。
我们以下讨论的所有流中都强行令 ,当 时可以转化为 ,那么可以给 间赋一个流量下界 从而转化为下面要说的上下界网络流。
对 我们可以当作 中不存在 这条边,虽然理论描述并不需要这样,但是这对算法效率有很大影响, 将会以 的形式呈现在复杂度里。
最大 / 小流
我们需要求给定网络在给定容量限制下的最大 / 小的可行流流量。观察网络总流量的定义式,最小流显然是把 当源 当汇求得的最大流的相反数,于是只考虑如何求最大流即可。
EK 算法
最大流算法有很多种,其中一类叫做增广路算法,基于最大流最小割定理不断找增广路求解。EK 算法是其中最基础的一个算法。
残量网络和增广路
对于任意一个流函数 ,我们将该图上容量函数为 的网络称为该流函数的残量网络。其中显然可能有些 ,那么在该残量网络中不将边 视为存在者。
增广路是一条在残量网络上的 路径,显然把这条增广路的每条边都多流上其中最小的容量函数值得到新流函数 ,会让原流函数的流量增加,并且该增广路断掉(因为至少有一条边的 值变成 了),同时也会有某些 增加(因为其反向边的流量可能增加,从而该边流量减少)从而有新边出生。这一沿增广路增加总流量的过程称为增广。
割和最大流最小割定理
一个网络(将 当作边 的边权)的割是一个两个点集 满足 且 。这个割的大小为 。
最大流最小割定理:同一个网络上的最大流等于最小割。
证明:考虑任意一个可行流 和任意一个割。 将斜对称和流量守恒分别在 内部边和 上作用容易得到, 的流量等于割边上的流量和。又由容量限制有,任意一个可行流的流量要小于等于任意一个割的大小,即最大流小于等于最小割。那么显然只需要找到一组可行流和割满足大小相等即可证明该定理。
那显然一个对应残量网络上没有 路径的可行流满足该流等于最小割。那么如何证明一定有这样的可行流呢。只需要反证,如果没有的话就可以一直增广,而每次增广必定带来总流量的增加,那么最大流就是正无穷。而由于容量限制的存在(我们不考虑有 的情况,在 OI 中显然可以用 inf
(一个足够大的有限值)代替),最大流显然是有限的,矛盾,得证。
算法过程
就不停的找增广路增广,找增广路每次用 bfs 找长度最小的。直到找不到增广路的时候,由最大流最小割定理的证明过程显然可知此时是最大流。
时间复杂度
,实际上异常跑不满。
引理:一次增广后,残量网络上 到每个点的最短距离都会不减。
证明:反证。假设存在一个点 ,增广前后的最短路分别为 ,满足 。不妨假设 是增广后的残量网络上 的最短路上第一个满足最短距离减少的点,那么对它在该最短路上的上一个点 显然有 。而又显然有 。我们假设增广前残量网络上 ,那么显然有 ,于是有 ,矛盾,于是得到 。那么是如何做到增广前无 这条边,而增广后就有了呢,只能是因为增广前在 上进行了增广,于是有 即 ,结合 有 ,矛盾。得证。
复杂度证明:考虑对于每次增广,增广路上容量最小的边叫做关键边。显然一次增广过后,关键边会从残量网络上消失,要想再出现必须要满足其反向边被增广了。我们考虑一条边 前后两次被当作关键边增广,前一次最短路为 ,后一次的前一次(就是反向边 被增广的那次)为 ,那显然有 。根据引理有 即 。也就是说一条边前后两次被当作关键边,那么它的出发端点的最短路至少增加 。又由于最短路的上限是 ,所以每条边被当作关键边的次数是 ,总的增广次数就是 。而一次 bfs 显然是 ,于是总复杂度 ,得证。
Dinic 算法
上面讲的 EK 是最基础的算法,效率较低,在 OI 中并不常用,取而代之的是 Dinic。前面对 EK 的讲解纯属是为了辅助理解 Dinic。
同样是不停找增广路增广直到没有增广路为止。Dinic 在 EK 的基础上加上了以下两个优化:
- 多路增广:Dinic 分为很多轮增广,每轮同时进行很多次增广,这样来提高效率。考虑每轮先 bfs 一遍求出所有点的最短路,然后将图分层,只考虑满足 的边 ,这样子得到一个 DAG 就很好办。我们考虑从 开始携带 的流量来试图流的越多越好,往下 dfs。dfs 过程中,尽可能将手头的流发放到下一层的与之相连的点们,回溯的时候更新手头的流,没流了或没邻居可送了就返回,返回的值是实际送出的流。到 的时候就成功送出了手头的流,直接返回。
- 当前弧优化:因为每轮都是一个 DAG,所以显然每条边最多只会增广一次(注意必须是把当前边容量耗尽了才算被增广,如果手头流不够了那就不能跳过当前边)。而可能每次访问到这个点的时候都会从邻接表开头往后找到第一个没有被增广过的点,那么我们可以加上这么一个小优化:对每个点记录其邻接表的最后一个已被增广的位置来跳过已增广的边,称为「当前弧」。
时间复杂度
加上了这两个优化的 EK(也就是 Dinic)的复杂度是 ,也异常跑不满,但终究比 EK 快很多。这样的复杂度在 OI 中一般不会被卡,这是业界公约,除非出题人不想要他的🐎。还有一些其他效率更高的最大流算法,等我被卡毒瘤题了再学吧。
复杂度证明:首先证明增广轮数是 的。根据 EK 正确性证明过程可知一次增广后 到所有点的最短距离不减。那么我们只需要证明每轮增广后 的最短距离一定增加即可。考虑反证,假设存在一轮增广前后 最短距离不变,也就是增广后仍然存在一条 路径满足上面点的最短路依次为 。根据增广前后每个点最短路不减,增广前该路径上点的最短路一定依次小于等于 ,特殊地, 是不变的。那么很容易知道,增广前只存在最短路序列为 满足不存在前一项小于等于后一项 ,而如果是这样的话那就显然一定会在本轮被增广,于是得到增广前该路上的最短路序列一定存在前一项小于等于后一项 。而由于本轮增广只会在最短路相邻的点之间增加 / 删除边,那么这两项之间的边肯定是事先就有的,那么后一项的最短路就应该小于等于前一项的最短路 ,矛盾。
接下来我们来证明每轮增广的复杂度是 。显然在 dfs 的过程中,我们只需要考虑那些没有任何一条边伸出去的访问,即一条边都没伸出去就回溯了,这样的访问们对总复杂度的贡献显然是 到它的距离,即 。这样的访问只可能是两种:到了 或者刚到手头就没流。前者显然会使至少一条边被增广,当前弧改变;后者上一秒还有流,下一秒就没流了,这说明上一秒流过来的那条边容量为 ,也可以直接跳过,当前弧改变。而当前弧最多改变 次,每次改变都对应着一个 的贡献,于是每轮增广的复杂度是 。至此 的总复杂度得证。
btw Dinic 求二分图最大匹配的复杂度是 (我也不确定是不是对的,反正差不多,肯定是分数次幂级别),我目前也还没搞懂证明。不过管那么多干啥呢,二分图最大匹配你不最大流你写啥,匈牙利吗?
费用流
我们在原先的网络流定义上,给每条边加上一个「费用函数」的概念: 表示边 流单位流量的费用,需要满足 ,即反着流相当于正着退流(在 OI 中可能会有 和 都有给出值的情况,那就当作两条不同的边分别建反向边,当作重边)。那么对于一个可行流 ,它的费用是 ,即每对正反边只算一遍费用。
最小 / 大费用最大 / 小流
我们需要求出给定容量函数、费用函数下的给定网络的满足 是最大 / 小流时的费用最小 / 大的可行流 。最小流可以转化到最大流,那我们只需要考虑最小 / 大费用最大流即可(其实最小 & 大费用之间也可以很弱智的取相反数转化,不过我们不在此时转化,到下面 SPFA 改个不等号方向就可以了)。
EK 算法求初始残量网络不带负 / 正环的最小 / 大费用最大流
考虑上面所求的最大流的 EK 算法,将它的每次找最短增广路的 bfs 算法改成 SPFA(因为有负 / 正权边),每次求的是以费用为边权的最短 / 长增广路。这样子最终求出来的就是最小 / 大费用最大流。
正确性证明
(真就从一级标题到五级标题 wdnmd 我好 nb)
根据最大流最小割定理显然有求出来的是最大流。下面只要证求出来的是所有最大流中费用最小 / 大的那个,以最小为例,最大同理。
引理:一个可行流 是所有流量与之相等的可行流中费用最小的,当且仅当它所对应的残量网络中不存在负环。
证明:考虑两个流量相等的可行流 。由于它们流量相等,且满足可行流定义的后两条是有可减性的,有 是流量为 的可行流(不考虑容量限制)。那么 显然是由若干个流量相等的环叠加组成的(就是一堆流流一圈流回自己)。那么 的费用是负的(也就是 的费用小于 的费用)显然仅当其中存在边权和为负的正流环,也就是说从 变到 的时候所增广于其上的 对应的残量网络有负环。于是得到,一个流的残量网络上有负环,就一定不是流量与之相等的可行流中费用最小的,可以在负环上增广得到更小的;而如果不是费用最小的,那就一定存在更小的流使 费用为负,那就一定在残量网络上有负环。得证。
算法正确性证明:我们考虑归纳证,在算法过程中每一步的流都是所有流量与之相等的可行流中费用最小的。由于先决条件「初始残量网络不带负环」得到满足,初始的空流是满足上述命题的。接下来只要证从每个满足上述命题的流 进行一次增广得到 仍然满足上述命题。考虑反证,假设增广后的流不满足,存在流量等于它且费用更小的流 。那么 这两个差流大小相等, 费用更小。由于 的部分流量是相等的,而 取的是最短路,所以 的 的费用一定大于等于 的 的费用。而 的总费用又更小,且 中只有 这一个要素,那么 中一定有负环。于是 的残量网络中一定有负环,和「 满足上述命题」矛盾,得证。
顺带也证明了该算法的可实现性:任意时候 SPFA 所处理于其上的图都不含负环,于是 SPFA 是可以做的。
时间复杂度
,其中 是最大流流量,且异常异常异常跑不满。(btw 有一种势能算法可以 SPFA -> Dijkstra 做到 ,无疑是更快了,不过我学不动了,卡毒瘤题再学吧)
这就很好理解了吧……最多增广 次,每次 SPFA 。同理改造版的费用流 Dinic 也是 ,一切关于最短路的分析都失效了,因为边权值域被扩大了。那么此时 Dinic 比 EK 就快不了多少了,甚至会更慢,因为多路增广成功率大大降低了。而且 Dinic 加上费用概念后有些地方就变得未定义了,就很麻烦,于是 EK 才是 OI 圈内最小费用最大流的最常用算法。
「最大流不卡 Dinic,费用流不卡 EK」是完整的业界公约(
有负环的情况
这个解决的方法好像挺多的,白皮书上是消圈算法,但似乎效率和好写程度都挺差的。有一个不知道是谁提出来的很好用的利用上下界网络流(这个下面讲)的技术解决的方法:
我们考虑对于任意一条负权边,都用一个等价的方法表示它:设该边的容量限制为 ,那么先让它满流,即上下界 ,然后其反向边 用于退流,转化为有源汇上下界最小 / 大费用最大 / 小流。那你可能要问了,这不依然可能有负环吗?但是依照上下界网络流的解决方式,会把 这条边处理成 ,相当于在初始残量网络上不存在。那不就行了吗?复杂度不变,依然是原来的 EK 的复杂度。
最小 / 大费用可行流
这时候没有所求流是最大流的限制条件了,只要求在所有可行流中费用最小 / 大的。
那么如果图中没有负 / 正边(注意为什么加粗,昨天我以为的是环,而今天发现是谬论,如果这样的话那二分图最大权匹配就没有意义了)的话,那么空流,费用为 ,很显然达到了费用的下 / 上界。如果有的话,可以通过处理负环的技术(其实虽然可能没有负环,但是处理负环的技术能把所有负边都处理掉)转化为有源汇上下界最小 / 大费用可行流,这个下面再讲。
无源汇最小 / 大费用可行流
既然可行流了,那么可以拓展到无源汇的情况,即每个点都要满足流量守恒。
同上,转化为无源汇上下界最小 / 大费用可行流。
上下界网络流
在上面所提及的最广的网络流概念中,加上了流量下界的概念:给定 函数,可行流的容量限制改为 。我们需要求各种上下界网络流问题。
不难发现无下界网络流就是一种特殊的上下界网络流,有 。然后如果 的话,我们可以转化为 转化为无下界网络流。不难发现这样一个哲学道理:无下界网络流是初始流(即空流)是可行流的特殊的上下界网络流。
无源汇上下界(最小 / 大费用)可行流
无源汇就是每个点都要满足流量守恒。这样就没有了总流量的概念,于是只有可行流了。
先不考虑费用,毕竟费用流就是在最大流的 EK 上把 bfs 改成了 SPFA。
我们考虑先给每条边 流 的流量。但是这样不一定满足流量守恒。于是我们需要试图在剩下的 上流一点流使它变得流量守恒。
我们考虑每个点已经流的流量为 ,那么我们只需要在 上在该点处流 即可让该点满足流量守恒。于是我们可以把所有已经流的边用对点的总贡献的形式等效表达出来:新建一组源汇 ,如果 表示总体是流入,从 到该点连 ;否则是流出,从该点到 连 。然后把 叠加上去后,我们考虑是否能有一组可行流满足所有附加边都满流,也就是刚开始刚连完下界之后是可以配成流量守恒的。这只需要跑个最大流即可,判断是否满流(即最大流是否等于 连出的容量和),如果没满就无可行流,满了的话每条非附加边的流量加上 就是真实流量了。
带上费用的话,就附加边的费用是 ,然后易证跑最小 / 大费用最大流是满足费用最小 / 大的。建完图之后如果初始残量网络有负环的话就随便处理一下就转化成了初始残量网络无负环的上下界网络流,是不会出现无限循环的转化的哦。
有源汇上下界(最小 / 大费用)可行流
就从 连一条 的边,将汇的流输给源,转化为无源汇即可。这时候新连的边的流量就是总流量。
有源汇上下界(最小 / 大费用)最大 / 小流
思路是先求出任意一组可行流,然后调整。
求出一组可行流之后,又回到了上面说的「哲学问题」上面来:此时已经满足初始流是可行流了,那其实只需要再求一遍无下界的(最小 / 大费用)最大 / 小流即可。不难发现是在第一遍求可行流之后剩下来的残量网络上,以本来的源汇为源汇求流(注意要删除边 )。每条边的真实流量就是可行流量加上第二遍求的最大 / 小流的在这条边上的流量,真实费用就可行流和费用流相加。
然后此时也不需要担心第二遍求费用流的时候的负环问题,因为由费用流正确性可知,最终的残量网络上是无负环的。而第二遍跑费用流的初始残量网络,就是第一遍剩下来的残量网络再删掉一条边,那怎么可能有负环呢。
不带费用最大流模板题 code & 不带费用最小流模板题 code
番外篇
不难发现,网络流问题有四个要素:有 / 无源汇、有 / 无下界、是否带费用,可行流还是最大 / 小流。
我们把这 16 种一一枚举一遍:
- 无源汇无下界无费用可行流:弱智,空流就满足要求;
- 无源汇无下界无费用最大 / 小流:不存在,因为无源汇就没有总流量;
- 无源汇无下界最小 / 大费用可行流:即无源汇最小 / 大费用可行流;
- 无源汇无下界最小 / 大费用最大 / 小流:不存在;
- 无源汇上下界无费用可行流:即无源汇上下界可行流;
- 无源汇上下界无费用最大 / 小流:不存在;
- 无源汇上下界最小 / 大费用可行流;
- 无源汇上下界最小 / 大费用最大 / 小流:不存在;
- 有源汇无下界无费用可行流:弱智,空流;
- 有源汇无下界无费用最大 / 小流:即最大 / 小流;
- 有源汇无下界最小 / 大费用可行流:即最小 / 大费用可行流;
- 有源汇无下界最小 / 大费用最大 / 小流:即最小 / 大费用最大 / 小流;
- 有源汇上下界无费用可行流:即有源汇上下界可行流;
- 有源汇上下界无费用最大 / 小流:即有源汇上下界最大 / 小流;
- 有源汇上下界最小 / 大费用可行流;
- 有源汇上下界最小 / 大费用最大 / 小流。
有效的问题只有 10 个,其中 1 个最大流,3 个费用流,6 个上下界网络流,可见一一出现在了番外篇的上面。基本算法只有两个:最大流和最小费用最大流,带费用的是在不带费用的上面魔改。另外两个费用流都是转化到上下界去了,上下界的话可行流随便求,最大 / 小流就先求出可行流再随便求最大 / 小流,带费用的话就敲个 SPFA 上去。
二分图
一个二分图是一个无向图 ,满足存在 ,使得 和 之间没有边相连。
想要判定一个图是否二分图的话随便染色就可以了,这个小学二年级就学过了。
二分图的匹配
一个二分图的匹配是一个边集 满足 中任意两条边没有公共点。
二分图最大匹配
这玩意非常简单,只需要建网络流即可。考虑新增一个源点一个汇点,把 排成两排,源点向第一排、第二排向汇点连 边,第一排向第二排连 中的边(容量为 )。这样最大流就是该二分图的最大匹配。
前面 Dinic 的时候说过,这样二分图最大匹配建出来的网络跑 Dinic 是 的(待核实)。还有一种匈牙利算法,,劣于 Dinic,没学了(其实明明早就学过好不好只是忘掉了)。
二分图最优匹配
给每条边加上了权值 。
二分图最大权最大匹配
需要求出所有最大匹配中权值和最大的。
那这个就把权值当成费用建进去然后求最大费用最大流即可。二分图建网络本身不可能有环,所以更不用考虑正环的问题。
然后听说有个 的 KM 算法是专门求这个的,应该要比费用流优(费用流是 ),但暂时不想学。等卡毒瘤题再学吧。
二分图最大权匹配
不需要是最大匹配了。那就跑最大费用可行流即可。这个正环问题就不存在上面说的了,因为最大费用可行流本身就要消正边。
二分图多重匹配
这个东西扩展了二分图匹配的定义:本来的定义等价于每个点最多只能和一条匹配中的边关联,现改为对于点 最多关联 条边。
这就直接把源汇连向非源汇的边的容量改成 值即可,带不带费用通吃。最大流的情况下,这个容量不是 了,所以不满足 的复杂度。
匹配、边覆盖、独立集、点覆盖
给出无向图(注意不一定是二分图,是一般图)的四个概念的定义:
- 匹配:一个无向图的匹配是一个边集 满足 中任意两条边没有公共点;
- 边覆盖:一个无向图的边覆盖是一个边集 满足 所关联的点集等于 ;
- 独立集:一个无向图的独立集是一个点集 满足 中任意两个点不相连;
- 点覆盖:一个无向图的点覆盖是一个点点集 满足 所关联的边集等于 。
容易发现匹配和边覆盖是针对边集的,独立集和点覆盖是针对点集的。注意到四者的定义可以换一种等价的理解:每个点最多与一条边关联、每个点至少与一条边关联、每条边最多与一个点关联、每条边至少与一个点关联。那么显而易见地,前两个和后两个是两对孪生兄弟的关系。事实上,它们满足如下关系:
- 如果没有孤立点的话(有孤立点则无边覆盖),最大匹配与最小边覆盖的和等于 。证明:我们贪心地想:加上一条边可以多覆盖 个点。 个就算了; 个的话是最好,优先把极大的贡献 个的边集给搞出来,剩下来的点都用一条一条边来覆盖。那么前者显然就是最大匹配 ,后者就是 咯。那么最小边覆盖为 ,显然有 ,得证;
- 最大独立集与最小点覆盖的和等于 。证明:如果 是一个独立集,那么 显然是一个点覆盖,因为前者不对任何边做出覆盖的贡献;反之亦然。于是发现独立集和点覆盖满足双射关系,那么显然对最大独立集 有最小点覆盖为 ,得证。
那么最大匹配和最小边覆盖、最大独立集和最小点覆盖这两组中,每组只要知道一个就可以搞出另一个,具体方案的搞法通过证明过程容易得到。
对于一般图而言的话最大匹配的话,是有一个带花树算法的,我目前不想学,而且这也不在网络流与二分图的范围之内;二分图的最大匹配就直接按上述方法求就可以了。然后对于一般图的最大独立集和最小点覆盖是 NPC 问题,不可做;而对于二分图而言,有最大匹配等于最小点覆盖。
证明:结论是,Dinic 求解最大匹配所得的残量网络中, 不能到达的 中的点和 能到达的 中的点合起来是一个最小点覆盖。我们显然只要证明三件事情:
- 最小点覆盖大于等于最大匹配。这个就比较显然了吧,最大匹配中的边每个都必须用一个端点来覆盖,而且这些端点互不相同;
- 该方案是一个点覆盖。只要证不存在一条边,满足左端 能到达且右端 不能到达。考虑反证,假设有这样一条边。由于 能到达左端,所以该边一定未匹配,于是在残量网络中的方向是左指向右,于是右端 也能到达,矛盾;
- 该方案包含的点数等于最大匹配。由于 中选的点 都不能到达,所以一定是匹配边的左端。由于 中选的点 都能到达,而由于 Dinic 结束时不存在增广路,所以这些点都不能到达 ,所以一定是匹配边的右端。而一条匹配边不可能两端都被选,因为如果右端 能到达,那么左端 也能通过该匹配边到达,矛盾。于是得到该方案选的点数小于等于最大匹配。结合前两条可知该方案选的点数等于最大匹配。
综上,得证。
至此,我们已经可以求出二分图的最大匹配、最小边覆盖、最大独立集、最小点覆盖。
团
一个无向图的团是一个点集 满足 中任意两个点都相连。那么不难发现 是团当且仅当 在该图的补图中是独立集。于是转化一下就可以了,如果补图是二分图直接求。
其他模型
最小路径覆盖
最小不相交路径覆盖
对于一个 DAG ,一个路径集合 是它的一个不相交路径覆盖当且仅当所有点都被恰好一条路径覆盖。那么最小不相交路径覆盖就是满足 最小的 。
我们考虑初始方案为每个点单独为一个路径的方案,。然后考虑在最优 中,对于每条路径,两端的点一个没有入,一个没有出,其他的都有恰好一个入一个出。如果把一条边加到 里面的话,会将它的两端合并起来,一个入被占了,一个出被占了,并且 减一。那么容易想到求最多可以选多少条边。结合每个点的入和出各可以被占一次,可以想到二分图最大匹配。
我么把每个点都拆成两个点,一个表示入,一个表示出。原图上一条边,就从左端的出点连向右端的入点,构成一个无向二分图。这个二分图的最大匹配显然就是最多可以选的边数,答案就是 减去最大匹配。方案构造也显然。
最小可相交路径覆盖
定义改成所有点都被至少一条路径覆盖。
结论:对原图求传递闭包,如果 有路径就在新图上建边 。那么新图的最小不相交路径覆盖等于原图的最小可相交路径覆盖。
证明:对于新图的每个不相交路径覆盖,显然可以把每条被选边还原成在原图上的路径,得到若干个版本的路径数不变的原图的可相交路径覆盖。那么显然只要证,原图的每个可相交路径覆盖都可以被新图的至少一个不相交路径覆盖转化到。这个是显然的,得证。
方案构造也显然。
upd. 2020.1.14:今天偶然发现了一个新的用上下界网络流解决的方法。
考虑不相交的。我们考虑一条流表示一条路径,那么就每个点向源汇流 。然后每条边是 ,因为有点的限制护着呢。然后点只能被恰好访问一次,那就点边转化为 。然后求有源汇上下界最小流。
那么可相交的就把点边转化改成 即可。
虽然不相交的两种方法看起来差不多,但是可相交的感觉能把传递闭包的 优化到 ?
不会吧不会吧 我真就提出了一个前无古人的东西啊
upd. 2020.1.15:发现这个方法已经烂大街了,帖子(
最大权闭合子图
一个图 的子图 (其中 是 的出边集合)是 的闭合子图当且仅当 中的边全部指向 。求点权和最大的 (当然会有负权点啦,不然当你傻啦)。
我们可以考虑集合划分模型(这在 xht 博客和我的刷题笔记里都有提到)。对每个点,你有两条路,你是被选进闭合子图,还是不被选。由于要求最大权闭合子图,要转化为最小割,所以我们先提前计算总点权,然后计算删除的最小代价。那么显然, 连向每个点边权为该点点权,每个点连向 边权为 。
然后考虑闭合子图的限制怎么体现于其上。显然等价于,如果 ,那么 被选 不被选是不合法的。猪脑子也能想明白,只需连边 即可,边权为 表示无法割断。
但是这样是有负边的最小割,这是不可做的。于是我们对于所有负权点采用另一种处理方式,不对它进行费用提前计算,然后如果没选就没事,选了就把答案减去它点权的相反数。
最终可以总结成这样一个处理方式:在原图上,令所有边边权为 。将 连向所有正权点,边权为点权;将所有负权点连向 ,边权为点权的相反数。最大权闭合子图的点权和就是正权点权和减去最小割,方案是选择所有与 相连的点。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现