网络流详解

网络流

定义

网络流图定义

  1. 每条边有两个权值,容量和流量
  2. 流量不超过每条边的容量
  3. 流量守恒,每个点流进来和流出去的容量一样
  4. 源点和汇点容量无限

定义 E E E为边集, V V V为点集

最大流

∑ v ∈ V f ( s , v ) \sum _{v \in V} f(s,v) vVf(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=vVf(s,v)vVf(v,s)

由于一般构造的网络流图没有流向起点的边,所以一般不用管(但是分析的时候要考虑

问题:

  1. 有反向边的图如何转化使得最大流不变?

    如果有二元环,新建节点连边(拆点

    怎么拆?听甲鱼讲课啊QwQ

  2. 多源汇最大流

    连一个超级源点和一个超级汇点,原来的源点汇点连的边容量为 + i n f +inf +inf

    举个例子:二分图最大匹配

最大流建模

  1. 是否存在s到t可经过相同节点不经过相同边的两条路径

    边容量设置为1

  2. 是否存在不经过中间相同节点的两条路径

    点转化为边(拆成两个点中间连条边),容量设置为1

  3. 满足以上两种情况

    同时设置即可

可见最大流模型的一般建模思路是运用流的容量限制,使得题目中的约束得以满足,有时还需使用一些特殊的方法(如上的拆点)来满足题目的特别约束。

残量网络

容量为原容量减去流量

还包含所有原图中的反向边,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) ff(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'| ff=f+f

相当于把剩下可流的流量直接流掉

这个剩下的可能是撤销原来一条弧,增加另一个地方的新弧(反向边的作用

证明

说下思路

  1. 流量不超过容量限制

    显然,参考残量网络定义

  2. 流量守恒

    把全部拆开,显然各自流量守恒

    然后改变方向合在一起就证出来了

具体?听甲鱼讲课呀QwQ

求流量

大概是把正向子图和反向子图增广拆开

然后合并4项和两项,得到在并图中增广就可以了

增广路

残量网络中从源到汇中的一条简单路径,一个边集

流量相当于残量网络中的瓶颈,即每条边容量的最小值

结论

  1. 增广之后流量增加

    运用上面的引理,

    ∣ f ↑ f p ∣ = ∣ f ∣ + ∣ f p ∣ |f↑f_p| = |f| +|f_p| ffp=f+fp

    然后对于任意增广路, ∣ f p ∣ > 1 |f_p|>1 fp>1

    不然就不事增广路力(不是一条路径

  2. 当找不到增广路时当前流是最大流

    这个证明有点复杂

    于是我们通过此问题引入新概念

即把 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)=uSvTf(u,v)uSvTf(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=vVf(s,v)vVf(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) =vVf(s,v)vVf(v,s)+uSsvVf(u,v)uSsvVf(u,v)vVuSsf(v,u)+vVuSsf(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) =uSvVf(u,v)uSsvVf(u,v)vVuSf(v,u)+vVuSsf(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) =uSvTf(u,v)+uSvSf(u,v)uSsvVf(u,v)vTuSf(v,u)vSuSf(v,u)+vVuSsf(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) =uSvTf(u,v)uSvTf(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必定是最小割——③

    这三个命题等价

证明

  1. 证明①推②:

    令④为存在 ∣ f 2 ∣ > ∣ f ∣ |f_2|>|f| f2>f

    因为 f f f是当前的最大流,所以①成立时④不成立

    参考增广路的定义,存在增广路与可以构造 ∣ f 2 ∣ > ∣ f ∣ |f_2|>|f| f2>f f f f为当前流量),即②的否命题与④成逆否命题

    当①成立时,④不成立,②的否命题不成立,②成立

  2. 构造点集 S S S s s s在残量网络上能够到达的点集, T = V − S T=V-S T=VS,定义那么 t t t一定在 T T T中( T T T中至少有一个 t t t), ( S , T ) (S,T) (S,T)是一个割

    即当②成立时③成立

  3. 先康康上面的推论

    高中数学告诉我们,两边取任意,左边的最大值就等于右边的最小值

    于是有最大流等于最小割

    即最小割是最大流的充分条件,当③成立时①成立

由上面三个结论可以得到它们是互相的充要条件

网络流算法

Ford-Fulkerson

每次用BFS找任意一条增广路然后增加流量直到残量网络中s与t不连通

很naiive

Edmonds-Karp

每次寻找最短的增广路(BFS)

引理

增广前后s到每个点的距离不降

选取 v v v使得 d f ′ ( v ) df'(v) df(v) 是d下降的节点中最小的

则有 d f ′ ( v ) &lt; d f ( v ) df&#x27;(v) &lt;df(v) df(v)<df(v)

设u为v的前驱节点,则 d f ′ ( u ) &lt; d f ′ ( v ) df&#x27;(u) &lt;df&#x27;(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&#x27;(u)+1=df&#x27;(v) df(v)df(u)+1df(u)+1=df(v)

矛盾,所以不在

因为 d f ( v ) df(v) df(v)在本次变化,所以 ( u , v ) ∈ E f ′ (u,v) \in Ef&#x27; (u,v)Ef,

即有 d f ( v ) = d f ( u ) − 1 &lt; = d f ′ ( u ) − 1 = d f ′ ( v ) − 2 df(v)=df(u)-1&lt;=df&#x27;(u)-1=df&#x27;(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)

单位容量网络

  1. 增广次数不超过 E 1 2 E^{\frac{1}{2}} E21

    1. d ( t ) ≤ E 1 2 d(t)\le E^{\frac{1}{2}} d(t)E21

      增广至少 E 1 2 E^{\frac{1}{2}} E21

    2. 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,即边数为两层之间的割的容量 &gt; &gt; >割的流量 = = =残量网络最大流

      所以 d d d的递增不超过 E 1 2 E^\frac{1}{2} E21次,即增广次数

  2. 增广次数不超过 V 2 3 V^{\frac{2}{3}} V32

    1. d ( t ) ≤ V 2 3 d(t)\leq V^{\frac{2}{3}} d(t)V32

    2. 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

      同上,容量 &gt; &gt; >最小割等于最大流,于是增广不超过 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(Emin(V32,E21))

单位网络

  1. d ( t ) ≤ V 1 2 d(t)\leq V^{\frac{1}{2}} d(t)V21

  2. 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=w1w2

W + X = w 1 − w 2 + x 1 + x 2 W+X=w_1-w_2+x_1+x_2 W+X=w1w2+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=SUMX,“图S中所有点的权值和” = “整个图中所有正权值之和” - “割集中所有边权值和”

然后,因为SUM为定值,只要我们取最小割,则“图S中所有点的权值和”就是最大的,即此时图S为图S为最大权闭合子图

这谁想得到啊,,,

海拔

左上点海拔0,右下1,显然是左上一堆点都是0,右下一堆是1,然后取0和1交界处最小值就可以了,暴力DINIC会T

可以转对偶图然后跑最短路

后记

什么?你问我为什么没有后面的题了?

当然是因为我只是一个刚拿到普及奖的蒟蒻啊QwQ

集训以来首次自闭祭

先去搞字符串了

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值