一些简单的说明.
基本的东西都烂大街了,这里大概会写一些不那么基本的东西,所以想学基本网络流的就不用看了.
一.网络流基本概念.
(无源汇)网络:网络是一张图 G = ( V , E ) G=(V,E) G=(V,E),每条边 ( x , y ) ∈ E (x,y)\in E (x,y)∈E都有一个流量上限 f ( x , y ) f(x,y) f(x,y).
流函数:一个流函数是一个定义在网络 G = ( V , E ) G=(V,E) G=(V,E)的边上的实值函数 F ( x , y ) F(x,y) F(x,y),满足:
容量限制:对于任意 ( x , y ) ∈ E (x,y)\in E (x,y)∈E,满足 0 ≤ F ( x , y ) ≤ f ( x , y ) 0\leq F(x,y)\leq f(x,y) 0≤F(x,y)≤f(x,y).
斜对称性:对于任意 ( x , y ) ∈ E (x,y)\in E (x,y)∈E,满足 F ( y , x ) = − F ( x , y ) F(y,x)=-F(x,y) F(y,x)=−F(x,y),即使并不存在 ( y , x ) (y,x) (y,x)这条边.
流量平衡:对于任意一个点 k k k,有:
∑ x , ( x , k ) ∈ E F ( x , k ) = ∑ y , ( k , y ) ∈ E F ( k , y ) \sum_{x,(x,k)\in E}F(x,k)=\sum_{y,(k,y)\in E}F(k,y) x,(x,k)∈E∑F(x,k)=y,(k,y)∈E∑F(k,y)
(有源汇)网络:在无源汇网络的基础上,增加两个点 S , T S,T S,T, S S S为源点, T T T为汇点.这两个点不满足流量平衡,但有:
∑ x , ( S , x ) ∈ E F ( S , x ) = ∑ y , ( y , T ) ∈ E F ( y , T ) \sum_{x,(S,x)\in E}F(S,x)=\sum_{y,(y,T)\in E}F(y,T) x,(S,x)∈E∑F(S,x)=y,(y,T)∈E∑F(y,T)
我们可以称之为全局流量平衡.
接下来若无特殊说明,所有的网络指的都是有源汇网络,源点和汇点分别为 S , T S,T S,T.
网络的流量:我们将一个网络 G = ( V , E ) G=(V,E) G=(V,E)的流量 F ( G ) F(G) F(G)定义为:
F ( G ) = ∑ x , ( S , x ) ∈ E F ( S , x ) = ∑ y , ( y , T ) ∈ E F ( y , T ) F(G)=\sum_{x,(S,x)\in E}F(S,x)=\sum_{y,(y,T)\in E}F(y,T) F(G)=x,(S,x)∈E∑F(S,x)=y,(y,T)∈E∑F(y,T)
其中 F ( x , y ) F(x,y) F(x,y)可以是网络 G G G的任意一个合法的流函数,也就是说一个网络可以有不止一个流量.
最大流:最大流指的是使得一个网络的流量最大的流函数.
不过通常我们指的最大流都是一个网络在最大流时的流量.
二.求解最大流.
懒得写一大堆奇奇怪怪的算法介绍了,想知道算法原理的百度吧,这里就简答写一下思路和一些概念.
増广路:増广路是一条路径 S , x 1 , x 2 , ⋯ , x k , T S,x_1,x_2,\cdots,x_k,T S,x1,x2,⋯,xk,T,满足对于任意 1 ≤ i < k 1\leq i
反向边:对于网络中的每条边 ( x , y ) ∈ E (x,y)\in E (x,y)∈E,我们都建立一条反向边 ( y , x ) (y,x) (y,x)使得 f ( y , x ) = f ( x , y ) , F ( x , y ) + F ( y , x ) = f ( x , y ) = f ( y , x ) f(y,x)=f(x,y),F(x,y)+F(y,x)=f(x,y)=f(y,x) f(y,x)=f(x,y),F(x,y)+F(y,x)=f(x,y)=f(y,x).
注意这里的反向边实际上对应了我们在斜对称性中引入的 ( y , x ) (y,x) (y,x),这里流量上限相同仅仅是为了避免负数的处理.
増广路算法:増广路算法的基本思路是每次找一条増广路,将増广路增加一个流量的同时给増广路上所有边的反向边减少一个流量,经过若干次调整后最终会得到最大流.
注意此时增广路可以将反向边也算上,用于反悔退流.
残余网络:假设我们现在已经有了一个流函数,那么将原网络所有边的流量上限减去当前流函数中的流量,得到的网络就是当前流函数对应的残余网络.
Dinic算法求解最大流的代码如下:
int dis[N+9];
queue<int>q;
bool Bfs_dis(int st,int td){
for (int i=1;i<=n;++i) dis[i]=0;
dis[st]=1;q.push(st);
for (;!q.empty();){
int t=q.front();q.pop();
for (int i=lin[t];i;i=e[i].next)
if (e[i].f&&!dis[e[i].y]) dis[e[i].y]=dis[t]+1,q.push(e[i].y);
}
return dis[td];
}
int cur[N+9];
int Dfs_flow(int k,int td,int f){
if (k==td||!f) return f;
int res=0;
for (int &i=cur[k];i;i=e[i].next)
if (e[i].f&&dis[k]+1==dis[e[i].y]){
int t=Dfs_flow(e[i].y,td,min(f,e[i].f));
if (!t) dis[e[i].y]=0;
f-=t;res+=t;
e[i].f-=t;e[i^1].f+=t;
if (!f) return res;
}
return res;
}
int Max_flow(int st,int td){
int res=0;
for (;Bfs_dis(st,td);res+=Dfs_flow(st,td,INF))
for (int i=1;i<=n;++i) cur[i]=lin[i];
return res;
}
三.费用流基本概念.
费用网络:在普通网络的基础上,费用网络的每条边 ( x , y ) ∈ E (x,y)\in E (x,y)∈E还有一个费用 v ( x , y ) v(x,y) v(x,y).
网络的费用:一个网络 G = ( V , E ) G=(V,E) G=(V,E)的费用 V ( G ) V(G) V(G)定义为:
V ( G ) = ∑ ( x , y ) ∈ E F ( x , y ) v ( x , y ) V(G)=\sum_{(x,y)\in E}F(x,y)v(x,y) V(G)=(x,y)∈E∑F(x,y)v(x,y)
同样的, F ( x , y ) F(x,y) F(x,y)也只需要是网络 G G G的一个合法流函数即可.
最小(大)费用可行流:在一个网络所有可行的流函数中,费用最小(大)的流函数.
最小(大)费用最大流:在一个网络所有可行的最大流中,费用最小(大)的流函数.
四.求解费用流.
由于作者的懒,这里也不介绍算法了.
EK算法求解费用流的代码如下:
int flow,value;
int dis[N+9],vis[N+9],pre[N+9],f[N+9];
queue<int>q;
bool Spfa(int st,int td){
for (int i=1;i<=n;++i) dis[i]=INF,vis[i]=0;
dis[st]=0;vis[st]=1;f[st]=INF;q.push(st);
for (;!q.empty();){
int t=q.front();q.pop();
vis[t]=0;
for (int i=lin[t];i;i=e[i].next)
if (e[i].f&&dis[t]+e[i].v<dis[e[i].y]){
dis[e[i].y]=dis[t]+e[i].v;
pre[e[i].y]=i;
f[e[i].y]=min(f[t],e[i].f);
if (!vis[e[i].y]) vis[e[i].y]=1,q.push(e[i].y);
}
}
return dis[td]^INF;
}
void Max_flow(int st,int td){
for (;Spfa(st,td);flow+=f[td],value+=f[td]*dis[td])
for (int k=td;k^st;k=e[pre[k]^1].y) e[pre[k]].f-=f[td],e[pre[k]^1].f+=f[td];
}
五.上下界网络流及其求解.
上下界(费用)网络:对于一张费用网络 G = ( V , E ) G=(V,E) G=(V,E),每条边 ( x , y ) = E (x,y)=E (x,y)=E增加了一个流量下界 l ( x , y ) l(x,y) l(x,y),此时任意一个合法的流函数必须满足 F ( x , y ) ≥ l ( x , y ) F(x,y)\geq l(x,y) F(x,y)≥l(x,y).
求解上下界网络流的基本思路是先去掉流量下界的影响,再满足流量平衡,最后再最优化流或费用的大小.
按照这个思路,我们依次解决无源汇上下界可行流、有源汇上下界可行流、有源汇上下界最大流、有源汇上下界最小流,至于上下界费用流只需要在普通流的基础上稍微讨论一下费用即可,这里不再赘述.
无源汇上下界可行流.
基本思路是一个先把每条边的下界流满,然后对于每一个点,如果进入的流多了就把流多的流进去,出去的流多了就把流多的流出.
我们建立超级源汇 S , T S,T S,T,定义 Δ f ( k ) = ∑ x , ( x , k ) ∈ E l ( x , k ) − ∑ y , ( k , y ) ∈ E l ( k , y ) \Delta f(k)=\sum_{x,(x,k)\in E}l(x,k)-\sum_{y,(k,y)\in E}l(k,y) Δf(k)=∑x,(x,k)∈El(x,k)−∑y,(k,y)∈El(k,y),即进入 k k k的边的下界和减去 k k k出去的边的下界和.
若 Δ f ( k ) > 0 \Delta f(k)>0 Δf(k)>0则建立边 ( S , k ) (S,k) (S,k)且 f ( S , k ) = Δ f ( k ) f(S,k)=\Delta f(k) f(S,k)=Δf(k), Δ f ( k ) < 0 \Delta f(k)<0 Δf(k)<0则建立边 ( k , T ) (k,T) (k,T)且 f ( k , T ) = − Δ f ( k ) f(k,T)=-\Delta f(k) f(k,T)=−Δf(k).
最后跑一遍最大流判断一下是否满流即可.
有源汇上下界可行流.
假设原网络的源点和汇点分别为 s , t s,t s,t,我们发现只有 s , t s,t s,t不满足流量平衡.
那么我们再在无源汇上下界可行流的基础上加入一条边 ( t , s ) (t,s) (t,s)且 f ( t , s ) = + ∞ f(t,s)=+\infty f(t,s)=+∞,跑一遍最大流.
最后可行流的流量为 F ( t , s ) F(t,s) F(t,s).
有源汇上下界最大流.
于是我们先按照有源汇上下界可行流跑出一个可行的流.
接下来我们再在残余网络上拆除 ( t , s ) (t,s) (t,s)及其反向边,跑 s s s到 t t t的最大流,加上原来的可行流就是答案.
可行的原因是我们跑最大流并不会影响除 s , t s,t s,t外的点的流量平衡,同时下界已经去掉也不会使某条边的流量低于下界.
另一种做法是不拆除 ( t , s ) (t,s) (t,s),直接跑出最大流就是答案,因为 ( t , s ) (t,s) (t,s)的反向边会直接算上原来可行流的流量.
有源汇上下界最小流.
仍然是先按照有源汇上下界可行流跑出一个可行的流.
同样的我们拆除 ( t , s ) (t,s) (t,s)及其反向边,跑 t t t到 s s s的最大流表示退掉的流量,可行流减掉这个退掉的流量就是答案.
想要不拆除 ( t , s ) (t,s) (t,s)直接跑出答案也可以,我们直接用 + ∞ +\infty +∞减去 t t t到 s s s的最大流即为答案,看似在数学上不可行,但在计算机中我们使用一个非常大的常量表示 + ∞ +\infty +∞所以可行.
六.存在费用负环的最小费用最大流求解.
存在费用负环的最小费用最大流由于最短路算法无法使用朴素的増广路算法求解,而消圈算法效率太低容易TLE,所以我们使用一种利用上下界网络流的方法求解.
对于任意一条边 ( x , y ) ∈ E (x,y)\in E (x,y)∈E,若 v ( x , y ) < 0 v(x,y)<0 v(x,y)<0,我们考虑让其强制满流后退流.
简单来说,我们利用上面的上下界网络流理论,对于一条 v ( x , y ) < 0 v(x,y)<0 v(x,y)<0的边 ( x , y ) (x,y) (x,y),先建立一条上下界均为 f ( x , y ) f(x,y) f(x,y)的边,再建立一条边 ( y , x ) (y,x) (y,x)满足 f ( y , x ) = f ( x , y ) , v ( y , x ) = − v ( x , y ) f(y,x)=f(x,y),v(y,x)=-v(x,y) f(y,x)=f(x,y),v(y,x)=−v(x,y)用于退流即可.