文章目录
网络流
定义
网络流图定义
- 每条边有两个权值,容量和流量
- 流量不超过每条边的容量
- 流量守恒,每个点流进来和流出去的容量一样
- 源点和汇点容量无限
定义 E E E为边集, V V V为点集
最大流
∑ v ∈ V f ( s , v ) \sum _{v \in V} f(s,v) ∑v∈Vf(s,v) 最大
真实定义:
∣ f ∣ = ∑ v ∈ V f ( s , v ) − ∑ v ∈ V f ( v , s ) |f| = \sum _{v \in V} f(s,v) - \sum_{v \in V} f(v,s) ∣f∣=∑v∈Vf(s,v)−∑v∈Vf(v,s)
由于一般构造的网络流图没有流向起点的边,所以一般不用管(但是分析的时候要考虑
问题:
-
有反向边的图如何转化使得最大流不变?
如果有二元环,新建节点连边(拆点
怎么拆?听甲鱼讲课啊QwQ
-
多源汇最大流
连一个超级源点和一个超级汇点,原来的源点汇点连的边容量为 + i n f +inf +inf
举个例子:二分图最大匹配
最大流建模
-
是否存在s到t可经过相同节点不经过相同边的两条路径
边容量设置为1
-
是否存在不经过中间相同节点的两条路径
点转化为边(拆成两个点中间连条边),容量设置为1
-
满足以上两种情况
同时设置即可
可见最大流模型的一般建模思路是运用流的容量限制,使得题目中的约束得以满足,有时还需使用一些特殊的方法(如上的拆点)来满足题目的特别约束。
残量网络
容量为原容量减去流量
还包含所有原图中的反向边,c(v,u)=-c(u,v)
走反向边的时候,相当于把原来的流量减为0
增广
定义残量网络中的一个流 f’
f ↑ f ′ ( u , v ) = f ( u , v ) + f ′ ( u , v ) − f ′ ( v , u ) f ↑ f' (u,v)=f(u,v)+f'(u,v)-f'(v,u) f↑f′(u,v)=f(u,v)+f′(u,v)−f′(v,u)
什么意思呢?
如果残量网络上有这么一条增广路,使得从 s s s到 t t t的流量最小值 ≥ 1 \ge 1 ≥1(至少还有1的流量可以通过)
那么把这些流量加到最大流,更新最大流
引理
f ↑ f ′ = ∣ f ∣ + ∣ f ′ ∣ f ↑ f' = |f|+|f'| f↑f′=∣f∣+∣f′∣
相当于把剩下可流的流量直接流掉
这个剩下的可能是撤销原来一条弧,增加另一个地方的新弧(反向边的作用
证明
说下思路
-
流量不超过容量限制
显然,参考残量网络定义
-
流量守恒
把全部拆开,显然各自流量守恒
然后改变方向合在一起就证出来了
具体?听甲鱼讲课呀QwQ
求流量
大概是把正向子图和反向子图增广拆开
然后合并4项和两项,得到在并图中增广就可以了
增广路
残量网络中从源到汇中的一条简单路径,一个边集
流量相当于残量网络中的瓶颈,即每条边容量的最小值
结论
-
增广之后流量增加
运用上面的引理,
∣ f ↑ f p ∣ = ∣ f ∣ + ∣ f p ∣ |f↑f_p| = |f| +|f_p| ∣f↑fp∣=∣f∣+∣fp∣
然后对于任意增广路, ∣ f p ∣ > 1 |f_p|>1 ∣fp∣>1
不然就不事增广路力(不是一条路径
-
当找不到增广路时当前流是最大流
这个证明有点复杂
于是我们通过此问题引入新概念
割
即把 V V V划分成 S S S和 T T T两个子图,定义应该是一个边集,就是KaTeX parse error: Expected 'EOF', got '\and' at position 35: …{v\in T} (u,v) \̲a̲n̲d̲ ̲(v,u) \in E(超级不严谨
割的流量
f ( S , T ) = ∑ u ∈ S ∑ v ∈ T f ( u , v ) − ∑ u ∈ S ∑ v ∈ T f ( v , u ) f(S,T)=\sum _{u \in S}\sum _{v \in T} f(u,v) - \sum _{u \in S} \sum _{v \in T} f(v,u) f(S,T)=∑u∈S∑v∈Tf(u,v)−∑u∈S∑v∈Tf(v,u)
割的容量
$c(S,T)=\sum _{u \in S}\sum _{v \in T}c(u,v) $
最小割
所有割中容量最小的那个
引理2
对于流 f f f,任意割之间的流量不变
感性理解:流量守恒
还是证明一下吧
∣
f
∣
=
∑
v
∈
V
f
(
s
,
v
)
−
∑
v
∈
V
f
(
v
,
s
)
|f|=\sum _{v\in V} f(s,v) - \sum_{v\in V}f(v,s)
∣f∣=v∈V∑f(s,v)−v∈V∑f(v,s)
= ∑ v ∈ V f ( s , v ) − ∑ v ∈ V f ( v , s ) + ∑ u ∈ S − s ∑ v ∈ V f ( u , v ) − ∑ u ∈ S − s ∑ v ∈ V f ( u , v ) − ∑ v ∈ V ∑ u ∈ S − s f ( v , u ) + ∑ v ∈ V ∑ u ∈ S − s f ( v , u ) = \sum _{v\in V} f(s,v) - \sum_{v\in V}f(v,s)+\sum _{u \in S-s} \sum _{v\in V}f(u,v) -\sum _{u \in S-s} \sum _{v\in V}f(u,v)- \sum _{v\in V}\sum _{u \in S-s}f(v,u) + \sum _{v\in V}\sum _{u \in S-s}f(v,u) =v∈V∑f(s,v)−v∈V∑f(v,s)+u∈S−s∑v∈V∑f(u,v)−u∈S−s∑v∈V∑f(u,v)−v∈V∑u∈S−s∑f(v,u)+v∈V∑u∈S−s∑f(v,u)
= ∑ u ∈ S ∑ v ∈ V f ( u , v ) − ∑ u ∈ S − s ∑ v ∈ V f ( u , v ) − ∑ v ∈ V ∑ u ∈ S f ( v , u ) + ∑ v ∈ V ∑ u ∈ S − s f ( v , u ) =\sum _{u\in S} \sum _{v\in V} f(u,v)-\sum _{u \in S-s}\sum _{v\in V} f(u,v)- \sum _{v\in V}\sum _{u\in S} f(v,u)+\sum _{v\in V}\sum _{u \in S-s} f(v,u) =u∈S∑v∈V∑f(u,v)−u∈S−s∑v∈V∑f(u,v)−v∈V∑u∈S∑f(v,u)+v∈V∑u∈S−s∑f(v,u)
= ∑ u ∈ S ∑ v ∈ T f ( u , v ) + ∑ u ∈ S ∑ v ∈ S f ( u , v ) − ∑ u ∈ S − s ∑ v ∈ V f ( u , v ) − ∑ v ∈ T ∑ u ∈ S f ( v , u ) − ∑ v ∈ S ∑ u ∈ S f ( v , u ) + ∑ v ∈ V ∑ u ∈ S − s f ( v , u ) =\sum _{u\in S} \sum _{v\in T} f(u,v)+\sum _{u\in S} \sum _{v\in S} f(u,v) - \sum _{u \in S-s}\sum _{v\in V} f(u,v)- \sum _{v\in T}\sum _{u\in S} f(v,u)-\sum _{v\in S}\sum _{u\in S} f(v,u)+\sum _{v\in V}\sum _{u \in S-s} f(v,u) =u∈S∑v∈T∑f(u,v)+u∈S∑v∈S∑f(u,v)−u∈S−s∑v∈V∑f(u,v)−v∈T∑u∈S∑f(v,u)−v∈S∑u∈S∑f(v,u)+v∈V∑u∈S−s∑f(v,u)
然后2,3,5,6四项相消(换一下sigma顺序就一模一样了)
得到:
= ∑ u ∈ S ∑ v ∈ T f ( u , v ) − ∑ u ∈ S ∑ v ∈ T f ( v , u ) =\sum _{u \in S}\sum _{v \in T} f(u,v) - \sum _{u \in S} \sum _{v \in T} f(v,u) =∑u∈S∑v∈Tf(u,v)−∑u∈S∑v∈Tf(v,u)
= f ( u , v ) =f(u,v) =f(u,v)
推论
任意流 ∣ f ∣ |f| ∣f∣的流量不超过任意割的容量
∣ f ∣ = f ( S , T ) ≤ c ( S , T ) |f| =f(S,T)\leq c(S,T) ∣f∣=f(S,T)≤c(S,T)
很显然
最小割最大流定理
这个定理包含三个命题:
-
流 f f f是图 G G G的最大流——①
-
当前流 f 的残量网络 c f c_f cf上不存在增广路——②
-
存在某个割使得 ∣ f ∣ = c ( S , T ) |f| =c(S, T) ∣f∣=c(S,T)成立。由结论 2 2 2可知,满足条件的割 c c c必定是最小割——③
这三个命题等价
证明
-
证明①推②:
令④为存在 ∣ f 2 ∣ > ∣ f ∣ |f_2|>|f| ∣f2∣>∣f∣
因为 f f f是当前的最大流,所以①成立时④不成立
参考增广路的定义,存在增广路与可以构造 ∣ f 2 ∣ > ∣ f ∣ |f_2|>|f| ∣f2∣>∣f∣( f f f为当前流量),即②的否命题与④成逆否命题
当①成立时,④不成立,②的否命题不成立,②成立
-
构造点集 S S S为 s s s在残量网络上能够到达的点集, T = V − S T=V-S T=V−S,定义那么 t t t一定在 T T T中( T T T中至少有一个 t t t), ( S , T ) (S,T) (S,T)是一个割
即当②成立时③成立
-
先康康上面的推论
高中数学告诉我们,两边取任意,左边的最大值就等于右边的最小值
于是有最大流等于最小割
即最小割是最大流的充分条件,当③成立时①成立
由上面三个结论可以得到它们是互相的充要条件
网络流算法
Ford-Fulkerson
每次用BFS找任意一条增广路然后增加流量直到残量网络中s与t不连通
很naiive
Edmonds-Karp
每次寻找最短的增广路(BFS)
引理
增广前后s到每个点的距离不降
选取 v v v使得 d f ′ ( v ) df'(v) df′(v) 是d下降的节点中最小的
则有 d f ′ ( v ) < d f ( v ) df'(v) <df(v) df′(v)<df(v)
设u为v的前驱节点,则 d f ′ ( u ) < d f ′ ( v ) df'(u) <df'(v) df′(u)<df′(v)
然后证明 ( u , v ) (u,v) (u,v)不在增广前的网络 E f Ef Ef上
如果在, d f ( v ) ≤ d f ( u ) + 1 ≤ d f ′ ( u ) + 1 = d f ′ ( v ) df(v)\leq df(u)+1\leq df'(u)+1=df'(v) df(v)≤df(u)+1≤df′(u)+1=df′(v)
矛盾,所以不在
因为 d f ( v ) df(v) df(v)在本次变化,所以 ( u , v ) ∈ E f ′ (u,v) \in Ef' (u,v)∈Ef′,
即有 d f ( v ) = d f ( u ) − 1 < = d f ′ ( u ) − 1 = d f ′ ( v ) − 2 df(v)=df(u)-1<=df'(u)-1=df'(v)-2 df(v)=df(u)−1<=df′(u)−1=df′(v)−2
所以 v v v不存在,其逆命题成立
EK增广 O ( n m ) O(nm) O(nm)次
总 n m 2 nm^2 nm2
Dinic
d i n i c dinic dinic 的原理是先把原图分层,然后一次DFS找完当前残量网络中所有增广路,每次增广一个阻塞流
于是 d d d一定单增,所以最多增广 V V V次
又因为单次最大是 O ( V E ) O(VE) O(VE)的(多次经过的点会最多被E条边更新(每条边最多被增广一次),最大V个点都这样被更新)
于是总复杂度是 O ( V 2 E ) O(V^2E) O(V2E)也就是 O ( n 2 m ) O(n^2m) O(n2m)
搞个板子
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#define rep(i,a,b) for(register int i=(a);i<=(b);++i)
#define CLR(x) memset(x,0,sizeof(x))
#define setmi(x) memset(x,-1,sizeof(x))
using namespace std;
const int N = 200021;
struct node{
int v,w,nex;
}edge[N<<1];
int top=1,head[N],cur[N];
const int inf=192608170;
inline void add(int u,int v,int w){
edge[++top].v=v;
edge[top].w=w;
edge[top].nex=head[u];
head[u]=top;
}
inline int read(){
char ch=getchar();int x=0;int pos=1;
for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return pos?x:-x;
}
int n,m,s,t,ui,vi,wi;
class dinic{
private:
int level[N];
queue<int>q;
public:
inline int bfs(){
setmi(level);level[s]=0;
q.push(s);
while(!q.empty()){
int now=q.front();q.pop();
for(int i=head[now];i;i=edge[i].nex){
int v=edge[i].v;
if(level[v]==-1&&edge[i].w){
level[v]=level[now]+1;
q.push(v);
}
}
}
if(level[t]==-1) return 0;
else return 1;
}
inline int dfs(int now,int flow){
if(now==t||flow==0) return flow;
int res=flow;
for(register int &i=cur[now];i;i=edge[i].nex){
if(res<=0) break;
int v=edge[i].v;
if(edge[i].w&&level[v]==level[now]+1){
int away=dfs(v,min(edge[i].w,res));
res-=away,edge[i].w-=away,edge[i^1].w+=away;
}
}
cur[now]=head[now];
return flow-res;
}
inline int solve(){
int ans=0;
while(bfs()){
ans+=dfs(s,inf);
}
return ans;
}
}DI;
int main(){
n=read(),m=read(),s=read(),t=read();
rep(i,1,m){
ui=read(),vi=read(),wi=read();
add(ui,vi,wi);
add(vi,ui,0);
}
rep(i,1,n){
cur[i]=head[i];
}
printf("%d",DI.solve());
return 0;
}
中等常数,最大点64ms,不想卡
LCT优化
不会,待填坑
加上之后炒鸡块!(也就 n m log n nm\log n nmlogn)
当前弧优化
显然每条边只会增广一次,更新head数组即可
具体做法是复制一个head的cur(head分层时还有用)
然后这样写:for(int &i = cur[now] ; i ; i = edge[i].nex)
单位容量网络
-
增广次数不超过 E 1 2 E^{\frac{1}{2}} E21
-
d ( t ) ≤ E 1 2 d(t)\le E^{\frac{1}{2}} d(t)≤E21
增广至少 E 1 2 E^{\frac{1}{2}} E21次
-
d ( t ) ≥ E 1 2 d(t) \geq E^{\frac{1}{2}} d(t)≥E21
在递归到第二步时,至少已经走了 E 1 2 E^{\frac{1}{2}} E21层
所以至少有两层之间边数不超过 E 1 2 E^{\frac{1}{2}} E21,又因为每条边容量为1,即边数为两层之间的割的容量 > > >割的流量 = = =残量网络最大流
所以 d d d的递增不超过 E 1 2 E^\frac{1}{2} E21次,即增广次数
-
-
增广次数不超过 V 2 3 V^{\frac{2}{3}} V32
-
d ( t ) ≤ V 2 3 d(t)\leq V^{\frac{2}{3}} d(t)≤V32
-
d ( t ) ≥ V 2 3 d(t)\geq V^{\frac{2}{3}} d(t)≥V32
类似地,一定存在相邻的两层满足点数 ≤ V 1 3 \leq V^{\frac{1}{3}} ≤V31
于是边数一定 ≤ ( V 1 3 ) 2 = V 2 3 \leq (V^{\frac{1}{3}})^2=V^{\frac{2}{3}} ≤(V31)2=V32
同上,容量 > > >最小割等于最大流,于是增广不超过 V 2 3 V^{\frac{2}{3}} V32
-
于是增广次数小于 m i n ( V 2 3 , E 1 2 ) min(V^{\frac{2}{3}},E^{\frac{1}{2}}) min(V32,E21)
然后经过每个点和每条边经过的增广路数量不超过 E E E 个
于是总复杂度 O ( E ∗ m i n ( V 2 3 , E 1 2 ) ) O(E*min(V^{\frac{2}{3}},E^{\frac{1}{2}})) O(E∗min(V32,E21))
单位网络
-
d ( t ) ≤ V 1 2 d(t)\leq V^{\frac{1}{2}} d(t)≤V21次
-
d ( t ) ≥ V 1 2 d(t) \geq V^{\frac{1}{2}} d(t)≥V21
类似,可以找到大小 ≤ V 1 2 \leq V^{\frac{1}{2}} ≤V21的割
可以证明跑二分图匹配复杂度
例题
最大权闭合子图
选子图相当于把一个图割成两部分,代表选或者不选
建边方式:所有的正权值连S,负权值连T,原图边连inf(防止被割
最小割产生的图S和图T,图S为最大权闭合子图
证明:
割集中所有的边,不是连接在s上,就是连接在t上
我们记割集中,所有连接在s上的边的权值和为 x 1 x_1 x1,所有连接在t上的边的权值和为 x 2 x_2 x2,而割集中所有边权值和为 X = x 1 + x 2 X=x_1+x_2 X=x1+x2;
令图S中所有点的权值和为 W W W,记其中正权值之和为 w 1 w_1 w1,负权值之和为 − w 2 -w_2 −w2,故 W = w 1 − w 2 W=w_1-w_2 W=w1−w2;
而 W + X = w 1 − w 2 + x 1 + x 2 W+X=w_1-w_2+x_1+x_2 W+X=w1−w2+x1+x2,又因为 x 2 = w 2 x_2=w_2 x2=w2, W + X = w 1 + x 1 W+X = w_1 + x_1 W+X=w1+x1
而显然的, w 1 + x 1 w1+x1 w1+x1是整个图中所有正权值之和,记为 S U M SUM SUM
然后有 W = S U M − X W = SUM - X W=SUM−X,“图S中所有点的权值和” = “整个图中所有正权值之和” - “割集中所有边权值和”
然后,因为SUM为定值,只要我们取最小割,则“图S中所有点的权值和”就是最大的,即此时图S为图S为最大权闭合子图
这谁想得到啊,,,
海拔
左上点海拔0,右下1,显然是左上一堆点都是0,右下一堆是1,然后取0和1交界处最小值就可以了,暴力DINIC会T
可以转对偶图然后跑最短路
后记
什么?你问我为什么没有后面的题了?
当然是因为我只是一个刚拿到普及奖的蒟蒻啊QwQ
集训以来首次自闭祭
先去搞字符串了