网络流
基础知识
定义
一张 网络:由一个图和一个函数 (C: E o R) 组成。(C(e)) 表示一条边 (e) 的 容量。
其中有两个关键的点,称为 源点(S) 和 汇点(T)。
下面用 (C(x,y)) 表示 (x,y) 这条边的 (C) 函数值。对于其它定义域为边集的函数都写成这样。
一个合法的 流:考虑这样的一个函数 (f:E o R),满足:
- 流量平衡: (forall u eq S,T,sumlimits_{v o u} f(v,u)=sumlimits_{u o v} f(u,v))
- 斜对称性:(forall u o v, f(u,v)=-f(v,u))
- 流量限制:(forall u o v, f(u,v)le C(u,v))
可以推得:
- (sumlimits_{S o u} f(S,u)=sumlimits_{u o T} f(u,T))
把这个值称为这个流的 流量。
有一个形象的理解是,(S) 为自来水厂,(T) 是你家,每条边相当于是一个水管,带一个容量限制。然后中间有若干的中转站(并不能提供水)。流量就是流到你家里水的数量。
一类问题是,最大化流量。 称为 最大流问题。
一类问题是,有一个费用函数 (w:E o R),表示每条边每个单位的流量所需要付出的费用。在最大化流量的前提下,最小化代价。称为 最小费用最大流 问题。
此外,还有一类问题叫做 “最小割”。严格定义如下:
- 将点集 (V) 划分成 (A,B) 两个集合(即,(Acap B=empty, Acup B=V)),使得 (Sin A,Tin B)
- 定义割的大小为:(sumlimits_{uin A,vin B} c(u,v))。最小化这个东西。
换句话说,就是:切掉一些边使得 (S,T) 不连通,最小化切掉的边的边权和。
【定理】最大流=最小割
证明:首先显然每个流都$le $每个割。然后做完最大流的时候,在残量网络上,把 (S) 能到的那些点设为 (A) 集,剩下的设为 (B) 集,(A,B) 就构成一个最小割,且这个割的大小就等于最大流。
最大流 - Dinic算法
首先我们发现,“流”这个东西其实就是很多条从 (S o T) 的路径,每条路径流了一个流量,叠加起来,然后给反向边放一个负权就行了。总流量就是每条路径流的流量和。
注意到,“流”和“(S o T) 路径”都满足除了 (S,T) 外的点流量守恒。
那假设咱现在有一个流。它是最大流吗?怎么把它变更大?
有一个显然的想法是我再找一条路径,叠加上去。如果流完之后还能满足流量限制,那我们就可以把流量加上这条路径流的量。
这玩意可以转化为:每次流完之后,我们把一条边的容量设为它还剩下的流量 (C'(u,v)=C(u,v)-f(u,v))。这样得到的网络称为 残量网络。同时,这条路径被称为 增广路。
反之,如果我们找不到增广路,那就说明当前是最大流了。
那如果我们有一次流错了,导致我找不到增广路,但还不是最大流?有没有这种情况?
注意到我们每条边有一个负权的反边。那如果 (u o v) 流了一个流量 (f),那么残量网络上 (C'(v,u)=0-(-f)=f)。(注意到 (C) 的限制是针对 (u o v) 的,(v o u) 容量限制为 (0),如果没有另外加边的话)。如果我们有一个增广路流了这一条边,就相当于把这次 (u o v) 的流 反悔 了。
这个机制确实保证了正确性,但是复杂度与容量有关。如果容量 (1e9) 直接挂了。
Dinic算法就解决了这样一个问题:我每次先BFS把图分层,每次只从上一层流到下一层。
然后它就跑的飞快了。
板子
一些易错点:
- BFS中, 不要忘记返回值,以及dep和Q的清空;对于当前弧优化,记得把当前弧搞出来
- DFS也不要忘记返回值
- 网络流别忘记clear
- 网络流中不要忘记定义变量 S,T
DFS(S,INF)
F(i,1,tot) dis[i]=INF;
- 最大费用最大流,你应该判
dis[T]<=-INF
的时候 break,而不是dis[T]<0
题
通常,网络流题目并不难在写出来网络流(除非出题人卡常,要写一些比dinic快的网络流),而是把模型建出来。
最大权闭合子图模型
一个有向图中,每个点有一个权值,可能正可能负。选一个点,就要选这个点所有后继。请选择若干个点,满足条件,且权值和最大。
这就是 “最大权闭合子图” 模型。
可以采用最小割建图来解决这个问题。有两种常见的思想:割一条边代表选,以及,割一条边代表不选。
分析一波。对于这个问题,我们考虑:假设没有任何限制,那肯定就把所有正的全都选上。
但是我们选了某些正的点,可能相应的就要选一些负的点。
对 “选...就要选...” 进行一个联想:在一张图上,要把 (S,T) 割开,如果我要保留一些边,就必须割掉另外一些边。也就是 “保留...就要割...” 的模型。
对于每个正权的点,要选它,就要选另外一些点。把权值放在边上,就变成 “选...就要选...” 模型。
根据上面的联想,我们令正权点连的边, “保留” 为 “选”。那它后继应该有一些能到 (T) 的边,使得它能构成 “保留...就要割...” 模型。
而且后面这些边,应该反过来,是以 “割” 为 “选”。
注意到,“保留”为“选”,相当于“割”为不选。那我们先全选,减掉割,就行了。
后面以“割”为“选”,我们考虑能不能保持同步,也是用 “全选,减掉割” 的办法处理。
啪的动一下脑子:对于负权点 (-a),我们连一条权值为 (a) 的边。如果割掉,就表示选了这个负权点。好对啊!!!
那我们现在已经有了 “全选,减掉割” 这个idea了,并且,我们要把点权放在边上。
那我们具体怎么连边呢?考虑 “保留...就要割...” 模型,总体上大概是前者离 (S) 近,后者离 (T) 近。
那我们干脆把前者连到 (S),后者连到 (T)。也就是说,把正权接在 (S) 上,负权接在 (T) 上。对于 “选...就要选...”,直接连边就行。
仔细一想,这样好像就对了!
总结一下:
- 对于正权点 (u),权值为 (a_i),我们连边 (Sxrightarrow[]{a_i} u)
- 对于负权点 (u),权值为 (-a_i),我们连边 (uxrightarrow[]{a_i} T)
- 对于原图上的 (u o v),连边 (uxrightarrow[]{infin} v)
- 正权和 - 最小割,为答案
这是一个常见模型。有很多延伸应用。
板子:洛谷 3410, [网络流24题]太空飞行计划问题
最大权导出子图 / 最大密度子图(poj 3155)
最大权导出子图,很好理解。就是点和边都带权,找一个导出子图,使得权值和最大。
考虑导出子图这个事情:如果选了一个边,就要选它两边的点。
把边建出来点,那它就变成了最大权闭合子图。
定义一个导出子图的密度为:边数/点数。找到最大密度的子图。
考虑二分。假设密度能 (> ho),设边数、点数为 (E,V),则 (dfrac{E}{V}> ho)。
也就是说 (E- ho V> 0)。设边权为 (1),点权为 (- ho),找到最大权导出子图,看看是否 (>0)。
(注意要严格大于,因为如果是 (ge0),你不选也 (ge 0),没法限制)
然后卡卡精度就行了。
经典in-out拆点
对于一个点 (u),拆成 (u_1,u_2),(u_1 o u_2) 连一条边,边权为 (u) 的点权。
这样就可以把点转换成边,用边来做点。
SCOI2007 蜥蜴
我们发现这个东西很像一个最大流。但是限制不在边上,而是点:每个柱子有被经过次数的限制 (h(i,j))。
对于 ((i,j)) 位置的点,我们把它in-out拆点,然后中间那条边权设为 (h(i,j)),即可解决这个限制。
对于原图上 (u o v) 的边,连边 (u_2 o v_1) 即可。
洛谷1345
这题是一个“最小点割”:每个点带点权,割若干个点使得 (c_1,c_2) 不连通。最小化割掉点的权值。
令 (c_1,c_2) 为 (S,T)。我们把点in-out拆点后,把中间那个边权设为该点的点权。(u_2 o v_1) 的边权设为inf。
求这个图的最小割,显然只会割在点中间那个边上。我们发现它就和原图割点的方案一一对应。求这个最小割就行了。
三元匹配
有三类点,(A,B,C)。边只会是 (A o B,B o C) 类型的。
对于一个 (a,b,c),满足:
- (ain A,bin B,cin C)
- (a o b),(b o c) 之间,都有边
称 ((a,b,c)) 是一组三元匹配。一个点只能被匹配一次。请你选出最多的三元匹配。
(相当于把二分图匹配扩展一下)
根据二分图匹配的套路,对于 (ain A,cin C),我们连边 (S o a,b o T),容量为 (1),就可以限制 (a,c) 只被选一次。
但是 (b) 可能被选很多次,那咋办?我们不能靠 (S,T) 了,靠自己!我们自己裂开来,in-out拆点,中间连一条边,容量为 (1)。这样就可以限制它只被选一次了。
然后跑最大流即可。
这个技巧也可以解决更多元的匹配。
例题如:洛谷1402,1231 (其实算是双倍经验了)
环覆盖
对于一个有向图,“环覆盖”可以看成是入度与出度的匹配。
然后就直接连边做就行了,注意一个点可以匹配很多次,所以连到 (S/T) 的边容量为它的入/出度。
例题如 CF510E,也没见到别的。
二元选择
每个东西只有两种选择,选 (A) 或者选 (B)。两种选择有各自的收益。
还有若干关系:若...选择...,则有额外收益。
不需要像刚才那样拆成两个点,直接把每个点连 (S) 表示选 (A),连 (T) 表示选 (B) 即可。
关系另外处理
小M的作物 / 文理分科 / happiness
这三个题本质上是一个题,都可以在洛谷上找到(
概括一个共同的题意:
- 每个点二元选择,选 (A) 获得价值 (A_i),选 (B) 获得价值 (B_i)
- 有若干个关系。每个关系分 (A,B) 类型,用一个集合 (S_i) 和权值 (v_i) 描述。若 (S) 集合中所有人同时选了 (A/B),则额外获得 (v_i) 的收益
- 最大化总收益
按照二元选择的模型建图。然后我们用 “割” 代表 “不选”。
对于每个关系,观察它的形式(以 (A) 型举例):若干个点同时割掉到 (T) 的边,这个关系才能形成。
令关系也是“保留”代表“选”,这个就是上面提到的模型:“保留...就要割...”
那把关系 (i) 搞出来一个点 (p_i),(Sxrightarrow[]{v_i} p_i),(p_ixrightarrow[]{infin} x (forall xin S))。
这样,只有当 (S) 中所有元素都选 (A) (割掉 (B))的时候,才能选这个关系,符合题目的要求。
然后用全部权值和减去最小割,就是最大的收益了。
SHOI2007善意的投票 / JLOI2010冠军调查
先搞一个二元选择模型建图。接下来,与上题不同,我们要解决“不同”。
这个东西更加简单。我们用“割”表示“选”,那只要在 (u o v,v o u) 之间都连一个 (infin) 就行了。
这样 (u,v) 必须选相同,才能避免这个额外的代价。否则,就会有一条通路过去。
然后求最小割就行了。
多元选择拆点
有 (n) 个东西,都有很多个选项。我们可以把每一个选项拆点,解决选项之间的限制问题。
它可以结合距离限制模型,解决更多问题。
SCOI2007 修车
对于一个师傅,它可能会修 (1,2,3...n) 辆车。我们把这 (n) 种选择全都拆成点。
注意到它依次修 (k) 辆车,时间为 (a_1,a_2...a_k),总时间为 (a_k+2a_{k-1}+3a_{k-2}...+ka_1)。越靠后,系数越小。换句话说,系数是 “倒数第几个”。
那我们这么拆:对于这个师傅 (x),拆点 (x_1,x_2..x_n) 表示:修倒数第 (1),倒数第 (2)....倒数第 (n) 辆车。
那给它一个 (1,2,3...n) 的费用就行了。容量为 (1),表示修一辆车。
(S) 先连到一个 (S'),容量为 (n),表示必须修 (n) 辆车。然后 (S') 连到每个师傅。每个车再连到 (T),容量为 (1),表示每辆车恰好被修一次。
以下是某个同学代笔写的,与文章内容无关,但文笔太好了,让我们来欣赏一下。
lzj会站在这些车前面,他认为这些车修的不好,于是一个个教育这些师傅,朝问道,夕死可矣,在修车的时候没有注入灵魂,看不出人的傲骨,车乃大丈夫行天下之利器,辙及天南海北,反映的是一个人的精神和风骨,君子者,为天地立心,为生民立命,为往圣继绝学,为万世开太平,一个合格的修车夫,应饱含理想主义的信仰,做一名斯多葛派的信奉者,不灭人生而有之的飒踏和洒脱,在尘世面前,保持初心,而不是庸于俗世泯然芸生,心之所行,万物随之奔流,修车乃格物之道,正如王阳明的心学理念,需人神之悟道,皆物我合一。我们看穿车之本质,其属性为两个标量,在一维不可逆的时间体系逻辑中,我们需以lzj的自我基础元的意识世界为第一视角,从计算的本质——映射开始,领悟绝世大儒对此题的理解和悟道,总而言之,AprilGrimoire txdy !!!!!!1
距离限制模型
每个东西有若干个选项,第 (i) 个东西的选项有编号 (jin [1,m]),并且有权值 (v_{i,j})。首先我们用上一个模型,把这些选项拆点。
拆完点之后,东西之间有选项的限制。设 (i) 这个人选的选项是 (c_i)。有若干个限制,每个形如:(c_i-c_jle/ge k)。我们需要满足每个限制,然后使权值和最小或最大。
这个就是距离限制模型。
它有一些延伸,比如说我们要做 (|c_i-c_j|le k),就可以转化成 (c_i-c_jle k) 且 (c_j-c_ile k),再套用这个模型。
那它怎么做呢?
其实我们并不是把选项拆“点”,而是拆“边”。对于每个选项,我们拆出 (m+1) 个点,连成一条链。中间 (m) 条边的权值是每个选项的权值。(S) 到最开始的点,最后的点到 (T) ,有两条 (infin) 的边。然后我们认为 “割” 为 “选”。
形式化地,对于第 (i) 个东西,我们设它拆成的点是 (A_{i,1}...A_{i,m+1})。
如下建图:
称这玩意为东西 (i) 的 “选项链”。 我们把每个东西的 “选项链” 都建出来。
这是一个经典的建图,它有什么性质?
我们在链之间横向插边!
比如我们在 (A_{u,i}) 和 (A_{v,j}) 之间连一条 (infin) 边。那么,如果 (v) 选在 (j) 之前,(u) 就要选在 (i) 之前。否则就会有 (S o A_{u,i} o A_{v,j} o T) 这样一条通路。
对于一个 (d),考虑:(forall i),连边 (A_{u,i} o A_{v,i+d}) 。如果 (v) 选在了 (i),则 (u) 必须选在 (i-d) 之前。这就实现了 (c_v-c_uge d) 。
然后求最小割就是最小的权值和。
那么问题来了,如何求最大的权值和?
首先我们搞一个够大的数 (M),然后把每个 (v_{i,j}) 变成 (M-v_{i,j})。然后用 (M imes n) 减去最小割即可。
感性理解:假设默认可以得到 (M) 的收益,考虑每个选项 损失 的收益。让损失最小,就等价于权值和最大了。
直接应用:HNOI2013 切糕,codechef RIN
行列建点
适用于网格图的建图技巧。
把每行、每列都看成点,把位置 ((x,y)) 看成行与列的关系,建边。
一般题目难都难在想到这样建,以及处理关系呢。
大概就是这样的套路吧(笑)。
bzoj4883
把每个格子看做行与列连了一条边,然后要定向。指向的那个点就是这个格子控制的点。
那我们一共要选 (n+m) 个边和点。那很显然就是一个基环树森林。
用并查集就可以类似kruskal贪心的做了。
虽然不是网络流题,但可以根据这个题,熟悉一下行列建点是怎么建的。
洛谷4311
逆向思维。假设一开始每个位置都有士兵,最少删掉多少个士兵?
删掉一个士兵,相当于把它对应的行和列都减少了 (1) 的贡献,答案也可可以变小 (1)。这就像我们把这里原来的一条流给取消了,三条边的流量都 (-1) 且答案 (-1)。
我们把 (S) 连到行点,列点连到 (T)。对于中间的一个格子,连接它对应的行列点,容量为 (1)。
对于每行每列,我们把它连到 (S,T) 的边的容量,设置为它最多能删掉多少个士兵使得它能满足条件。
显然这张图的最大流就是最少删除的士兵数,拿总数减掉就行。
HEOI/TJOI2016 游戏
假设没有石头,答案就是 (min(n,m))。
我们可以把它看成是行点与列点的匹配。每个可以放炸弹的格子相当于连接了一个行点和一个列点,答案就是最大匹配。
这样就可以做仅有软石头的情况了。考虑硬石头咋做。
现在放了一个硬石头,考虑它的那一行(列同理),如果我们在左边和右边放了一个炸弹,我们发现没事。因为这个硬石头把它们隔开了。
那其实我们以为这是 “一行”,但其实并不是 “一行”,它相当于是裂开了,变成两 “小行”。在两个“小行”内部不能同时有炸弹,但是在“小行”之间没有限制。
因此我们可以灵活运用这个拆点,把行再拆开。给这些拆开来的行赋予一个新的编号。
同理,我们给拆开来的列也分配新的编号。
然后就对这些 “新行”,“新列” 做最大匹配就行了。
SCOI2015 小凸玩矩阵
每行每列选一个 $ o $ 行列匹配,直接行列建点。
那第 (k) 大怎么做?
先二分,设第 (k) 大能 (ge mid),那么 (ge mid) 的设为 (1),(<mid) 的设为 (0)。我们得选出 (k) 个以下的 (1)。
(1) 的个数其实就是行列的最大匹配数。然后就每次跑一遍二分图匹配,然后check一下就行了。
最小路径覆盖模型
不太会,我去学一学
杂题
网络流24题 最长不下降子序列问题
第一问显然是dp。第2,3问似乎不能dp了。
第2问很像一个最大流。我们给每个点加一个只能选一次的限制,用容量来限制就行。限制在点上,看来需要做一个 in-out 拆点。
我们要保证每一条流,都对应着一个LIS。怎么做呢?
考虑一个LIS,它上面的dp值应该是连续+1的,并且位置也是递增的。
那对于 (i<j,dp_i+1=dp_j),我们连边 (i_2 o j_1),容量为 (1)。然后最大流就是答案了。
对于第三问,把点 (1,n) 内部的限制与它们到 (S,T) 的容量限制变为 (infin),就行了。
CQOI2009 跳舞
这题相当于明示了用网络流吧。感觉好像对着网络流的意义建边就行了,建完发现不太行。
首先一个问题是,不好处理“不喜欢”的限制。那好办,把不喜欢拆出来一个点。然后它来一个容量限制 (k) 就行了。
由于喜欢和不喜欢都是相互的 (单恋人落泪),“喜欢”相互连,“不喜欢”相互连就行了,不存在喜欢连到不喜欢的情况。
还有一个问题是,我们求出来它最多配成多少对,但是并不能直接得知能不重复的完美匹配多少次。
那咋办呢?考虑二分!
首先二分性显然是有的。然后对于一个 (mid),匹配的对数应该至少是 (mid imes n),然后才能完美匹配 (mid) 次。
我们可以在 (S,T) 那边,给每个人加一个 (mid) 的容量限制,表示这个人最多参加 (mid) 轮跳舞。
此时流量最大是 (mid imes n),判断它是否等于 (mid imes n) 就行了。
容易证明如果流量为 (mid imes n),一定有解。
然后就二分做一下就没了。
ZJOI2009狼和羊的故事
很明显,有两种东西,根据上面做这么多题的经验,啪的一下想到:(S) 连到羊,狼连到 (T)
接下来我们要设置最少的篱笆使得狼和羊不连通。这显然就是一个最小割问题。而且狼和羊不连通,等价于 (S) 和 (T) 不连通。那转化都不用转化,只要每个点向周围连一条边,容量为 (1),就行了。
POI2005 KOS-Dicing
对于一个比赛 (a,b),相当于要从二者中选一个,对其胜利次数 (+1)。然后我们要最小化这个最大值。
最大值最小,啪的一下,二分。 (注意到确实有可二分性)
然后现在变成了:对于一个 (k) ,是否可以让每个人的胜利次数都 (le k)。
考虑网络流,每流到这个人一次就看成是次数 (+1)。对于限制,我们把这个人连到 (T),容量为 (k),就限制了它只能赢最多 (k) 次。
对于一个 “二选一”,在生活中也很常见:用一个“分流”模型,实现这个事情。
具体的说就是一个三叉结构。首先我们把每个游戏建成一个点 (g_i),设这场游戏里的两个人是 (a_i,b_i),那么连边 (S o g_i, g_i o a_i, g_i o b_i),容量都是 (1)。由于 (S o g_i) 的容量是 (1),那么这个流该去向何方,只能在 (a,b) 两者中选了,就实现了二选一这个事情。
然后看看每个 (S o g_i) 是否都有流量。它必须全都有流量,(k) 才合法。如果有某个 (g_i) 没流过来,那说明我们必须要把这一场比赛扔掉才能满足条件,而不能带上它一块满足条件,说明这个 (k) 太小了。
并不需要写个循环,只需要判断最大流 (=m) 即可。
网络流24题 方格取数问题
二分图带权最大独立集。(注意到网格图是二分图)
首先,看到“二分图”的这个“二”,我们就想到 (S,T)。把其中一部分连到 (S),另一部分连到 (T)。边权就是这个点的点权。
然后还有一个问题,有些点不能同时选,就是原来二分图上有边的两个点。如何限制不能同时选呢?
设“割”为“不选”。那两个东西同时选,就会保留两条边。保留两条边,如果给它中间加一条inf边,就不合法了。
那容易得到,给原来有边的两个点,加一个inf边,就能限制这两个点里面一定要割一个。
拿权值和减去最小割就行了。
poj1149 pigs
“任意调换顺序”,即,保持和不变的情况下,可以随便指定哪里多少猪。
观察网络流的过程。对于一个点,如果有一堆流过来了,那都可以“储存”在这个点上(参考上面自来水厂和中转站的理解),然后保持和不变的情况下,任意的流出去。
那其实我们可以把猪当成流。然后猪给了一个人,我们就把这里所有的猪,都暂存在人这里。人到汇点有一个边,带容量限制,表示这个人要的猪数量。那剩下的猪就会留在人那里,在保持和不变的情况下,任意分配。
那如果接下来还有人来买猪,就从上一个人连到这一个人就行了。这样就实现了猪在保持和不变的情况下任意分配这件事情。
然后跑最大流就是最多的卖猪的数量。
网络流24题/CTSC1999 星际转移问题
很显然,把人看成流。然后人就在星球之间流动,地球看做源点,月亮看做汇点。
但是我如果直接建图,流是流过去了,用了多少时间呢?不知道。而且不同时刻,有哪些边也不一样。
观察一下,当前有哪些太空船,从哪到哪,随时间规律的变化。
和时间有关,一拍脑袋,想到用分层图建图。然后这样也就解决了不同时刻边不一样的难题。
盗用洛谷题解里的一张图,
这张图非常清楚的讲明白了如何建图。但有一个不太对,就是每一层的月亮都要向 (T) 连一条边。
然后看看最大流是否等于地球上的人数即可。可以用二分,或者在残量网络上不断的加一层,都可以实现。
神仙题: [Neerc2016]Delight for a Cat
令睡觉为 (0),吃饭为 (1)。设 (i) 位置的状态为 (x_iin {0,1})。
那么对于每个区间,设和为 (S),我们可以得到:
(t_2le Sle k-t_1)。设 (L=t_2,R=k-t_1),那么 (Sin [L,R])。
拆开来写,
共 (2(n-k+1)) 个。
然后我们把不等式变成等式。怎么变呢?(age b),看成是 (a=b+x(xge0))。
对于每个 (Sge L),设 (S=L+y_i)。对于每个 (Sle R),设 (S=R-z_i)。
然后得到 (2(n-k+1)) 个等式:
一个转化:在最下面添加一个等式 (0=0) (废条件)。然后,对这些等式,做一个,差分!
得到:
这样是 (2(n-k+1)+1) 个等式。
可以手玩一下,发现:每个 (x_i,y_i,z_i) 都恰好出现两次。如果我们恰当的移项,恰好一次在左,一次在右出现!
如下是一种看起来挺好看的变形
接下来是更加妙妙的操作:把等式看成点,两边相等看做流量平衡!
然后,我们把左边看成流入,右边看成流出,对于每个变量,直接把流出点连向流入点就行了!!!
注意到我们还需要让选出来的 (x) 权值和最大。那考虑费用流。
我们默认全都睡觉,先加上睡觉的权值,然后每个 (x) 的权值是 (e_i-s_i)。
(y,z) 没有限制,容量为 (infin),费用为 (0)。
(x) 的容量为 (1) (只能取 (0/1)),费用为 (e_i-s_i)。
对于常数项 (L,R),容量为常数的值,费用为 (0)。
然后跑最大费用最大流,取费用即为答案。
神仙题: WC2007 剪刀石头布
如何计算三元环的数量?
对于一般图, 当然不好做,但这是一个竞赛图。我们考虑先任选三个点, 它们之间显然会有三条边。
但这三条边必须“接起来”,才能构成三元环,否则就不行。
什么情况是“接不起来”的?一想,发现,有一个点出度为2,就gg了。再一想发现,这玩意是充分必要的。也就是说,如果没有点出度为2, 就一定能构成三元环。
那就好办了,答案就是 (inom{n}{3}-sumlimits_{i=1}^{n} inom{d_i}{2}),其中 (d_i) 表示 (i) 点的出度。
现在我们有一些边 ((u,v)),要给它定向。这个事情等价于在 (u,v) 中选择一个,把它的出度 (+1)。
观察到, (d_i) 变成 (d_i+1) 后,它对答案的新增的贡献是 (-d_i)。
这是一个常识,因为:
(inom{n+1}{2}-inom{n}{2}=dfrac{n(n+1)-n(n-1)}{2}=n)
而我们要让答案尽可能的大,也就是减的尽量少。考虑最小费用最大流。
这里有一个不好处理的是, 贡献会随着不断的选择, 动态的变化。我们不能把所有选择放一块考虑了,联想到上面说的“多元选择拆点”, 以及修车师傅那个题, 考虑把每次选择拆开。
每个点 (u),可能被加 (0) 次,(1) 次,或者更多次。初始的贡献是 (-inom{d_u}{2})。加一次,新增贡献 (-d_u)。加两次,新增贡献 (-(d_{u}+1)),以此类推。
那我们把每个点都往 (T) 连一堆边,容量都为 (1),费用依次是 (d_u,(d_u+1),(d_u+2)...),表示它被加一次,加两次,加三次...所对应的情况。注意这里的费用是指“损失的”三元环数量,所以是正的。
对于每条边 (u,v),把它也建出一个点,设为 (p)。它要在 (u,v) 两个点中二选一,给它 (+1) ... 等下,咱好像见过!
什么?你没见过?那你没仔细看上文
同样用那个 “分流模型”,(Sxrightarrow[]{1} p),(pxrightarrow[]{1} u,v),费用都为 (0)。
这个图一定满流吗?想想发现,我们给每个点连到 (T) 的边都足够多,所以最后每条“边”(指它建出来的点 (p)) 一定都能有恰好 (1) 的流量。
最后,拿 (inom{n}{3}) 减去最大流前提下的最小费用,就是答案了。
怎么只有这么点题啊
在写了在写了
todo:
- 网络流24题
- 最小路径覆盖 相关问题