1. 程式人生 > 其它 >網路流——從入門到入土

網路流——從入門到入土

1. 網路流的基本概念

注: \(G\) 為流網路, \(f\) 為可行流, \(|f|\) 為可行流的大小。

1. 流網路

一個有向圖 \(G=(V,E)\) ,每一條邊都有流量限制 \(C(u,v)\) ,源點為 \(s\) ,匯點為 \(t\)

2. 可行流

設一個可行流為 \(f\) ,它需要滿足兩個限制:

1.容量限制:

\(\forall (u,v)\in E,0\leqslant f(u,v)\leqslant C(u,v)\)

對於每一條邊,它的流量一定是大於 \(0\) 小於流量限制的。

2.流量守恆:

\(\forall x\in V|\{s,t\},\sum\limits_{(u,x)\in E}f(u,x)=\sum\limits_{(x,v)\in E}f(x,v)\)

對於每一個點(除了源點和匯點),它收到的流量等於輸出的流量。

3. 可行流的大小

\(|f|=\sum\limits_{(s,v)\in E}f(s,v)-\sum\limits_{(v,s)\in E}f(v,s)\)

可行流的大小即為源點輸出的流量減去收到的流量(一般沒有連向源點的邊)。

4. 最大流

最大流,全稱為最大可行流

即為流網路中大小最大的可行流。

5. 殘留網路

對於每一個可行流 \(f\) ,都有一個殘留網路 \(G\) ,且可行流與殘留網路是一一對應的。

一般記為 \(G_f\)

1.性質

\(V_f=V\)

殘留網路包含原圖中的所有點。

\(E_f=E+E'\)

殘留網路包含原圖中的所有邊以及反向邊。

\(C'(u,v)\) 為殘留網路中每條邊的容量。

\(C'(u,v)=\begin{cases}C(u,v)-f(u,v)&(u,v)\in E\\f(v,u)&(v,u)\in E\end{cases}\)

若當前邊為正向邊,容量即為原容量減去現在的流量,否則即為現在的流量。

\(G_f\) 的可行流為 \(f'\)

\(f+f'\) 也是 \(G\) 的一個可行流。

2. 流網路的相加

\(\forall (u,v) \in E,f(u,v)\gets\begin{cases}f(u,v)+f'(u,v)&(u,v)\in E'\\f(u,v)-f'(v,u)&(v,u)\in E\end{cases}\)

對於每一條邊,若另一個流網路中存在與它相同方向的邊,則將兩流量相加,否則相減。

\(f+f'\)\(G\) 的一個可行流,那麼它需要滿足可行流的兩個條件。

1.容量限制

若對於 \((u,v)\in E\) ,有 \((u,v)\in E'\)

\(\Rightarrow 0\leqslant f'(u,v)\leqslant C'(u,v)=C(u,v)-f(u,v)\)

\(\Rightarrow 0\leqslant f'(u,v)\leqslant C(u,v)-f(u,v)\)

\(\Rightarrow 0\leqslant\color{red}{f'(u,v)+f(u,v)\leqslant C(u,v)}\)

若對於 \((u,v)\in E\) ,有 \((v,u)\in E'\)

\(\Rightarrow 0 \leqslant f'(u,v)\leqslant C'(u,v)=f(v,u)\leqslant C(v,u)\)

\(\Rightarrow 0 \leqslant\color{red}{f(v,u)-f'(u,v) \leqslant C(u,v)}\)

至此,可證明 \(f+f'\) 滿足容量限制。

2.流量守恆

對於 \(f\) 中的所有點,都滿足流量守恆。

\(f'\) 同樣滿足,而相加不改變守恆。

易得 \(f+f'\) 滿足流量守恆。

可得 \(|f+f'|=|f|+|f'|\)

所以殘留網路中的可行流是可以加到流網路的可行流中的。

可以推出如果殘留網路沒有可行流,流網路一定是最大流。

6. 增廣路

在殘留網路裡面,從源點出發,沿著容量大於 \(0\) 的邊走,如果可以走到匯點,那麼這條邊是增廣路。

增廣路是無環無交點的簡單路徑。

對於一個可行流 \(f\) ,若殘留網路 \(G_f\) 中沒有增廣路,那麼 \(f\) 是最大流。

7. 流網路的割

一般的,設流網路的兩個點集為 \(X\)\(Y\)

可得 \(f(X,Y)=\sum\limits_{u\in X}\sum\limits_{v\in Y}f(u,v)-\sum\limits_{u\in Y}\sum\limits_{v\in X}f(u,v)\)

性質一: \(f(X,Y)=-f(Y,X)\)

性質二: \(f(X,X)=0\)

性質三: \(f(Z,X\bigcup Y)=f(Z,X)+f(Z,Y)\{X\bigcup Y=\varnothing\}\)

對於流網路 \(G=(V,E)\) ,將 \(V\) 分為 \(S\)\(T\)

滿足 \(S\bigcup T=V\)\(S\bigcap T=\varnothing\)\(s\in S\)\(t\in T\)

1. 割的容量

\(C(S,T)=\sum\limits_{u\in S}\sum\limits_{v\in T}C(u,v)\)

割的容量為從 \(S\)\(T\) 的邊的容量之和。

最小割指的是容量最小的割

2. 割的流量

\(f(S,T)=\sum\limits_{u\in S}\sum\limits_{v\in T}f(u,v)-\sum\limits_{u\in T}\sum\limits_{v\in S}f(u,v)\)

割的流量為從 \(S\)\(T\) 的邊的流量之和減去從 \(T\)\(S\) 的邊的流量之和。

3. 割的性質

\(\forall \left[S,T\right],\forall f,f(S,T)\leqslant C(S,T)\)

對於每一個割和每一個可行流,割的流量小於等於割的容量。

\(f(S,T)=\sum\limits_{u\in S}\sum\limits_{v\in T}f(u,v)-\sum\limits_{u\in T}\sum\limits_{v\in S}f(u,v)\)

\(\Rightarrow f(S,T)\leqslant\sum\limits_{u\in S}\sum\limits_{v\in T}f(u,v)\)

\(\because \sum\limits_{u\in S}\sum\limits_{v\in T}f(u,v)\leqslant \sum\limits_{u\in S}\sum\limits_{v\in T}C(u,v)=C(S,T)\)

\(\Rightarrow \color{red}{f(S,T)\leqslant C(S,T)}\)

\(\forall [S,T],\forall f,f(S,T)=|f|\)

對於每一個割和每一個可行流,割的容量等於可行流的大小。

\(f(S,V)=f(S,S)+f(S,T)\) (性質一)

\(\Rightarrow f(S,T)=f(S,V)-f(S,S)\)

\(\Rightarrow f(S,T)=f(S,V)\)

\(\Rightarrow f(S,T)=f(\{s\},V)+f(S-\{s\},V)\)

\(S'=S-\{s\}\)

\(\because f(S',V)=\sum\limits_{u\in S'}\sum\limits_{v\in V}f(u,v)-\sum\limits_{u\in S'}\sum\limits_{v\in V}f(v,u)\)

\(\Rightarrow f(S',V)=\sum\limits_{u\in S'}\big(\sum\limits_{v\in V}f(u,v)-\sum\limits_{v\in V}f(v,u)\big)=0\)

\(\therefore f(S,T)=f(s,V)=|f|\)

\(\Rightarrow \color{red}{f(S,T)=|f|}\)

綜上可以推出:\(|f|\leqslant C(S,T)\)

即為最大流\(\leqslant\)最小割

8. 最大流最小割定理

對於流網路 \(G=(V,E)\) ,同時滿足下面三個條件。

1. \(f\) 是最大流
2. \(G_f\) 中不存在增廣路
3. \(\exists \left[S,T\right],|f|=C(S,T)\)

\(1\Rightarrow2\)

\(f\) 為當前可行流,若存在增廣路 \(f'\) ,那麼 \(|f+f'|\geqslant|f|\)

\(2\Rightarrow3\)

\(G_f\) 中從 \(s\) 出發沿著容量大於 \(0\) 的邊走到的所有的點均在 \(S\) 中。

\(T=V-S\)

\(\forall (x,y)\{x\in S,y\in T\},f(x,y)=C(x,y)\)

\(\forall (a,b)\{a\in T,b\in S\},f(a,b)=0\)

\(\because |f|=f(S,T)\)

\(\Rightarrow |f|=\sum\limits_{u\in S}\sum\limits_{v\in T}f(u,v)-\sum\limits_{u\in S}\sum\limits_{v\in T}f(v,u)\)

\(\Rightarrow |f|=\sum\limits_{u\in S}\sum\limits_{v\in T}C(u,v)=C(S,T)\)

\(3\Rightarrow1\)

\(|f|=C(S,T)\geqslant|f_{max}|\)

\(\because |f|=|f_{max}|\)

\(\therefore |f|=C(S,T)\)

最大流等於最小割

2. 網路流的模板

1. FF

因為最大流中沒有增廣路,所以可以通過不斷的找增廣路來找到原圖的最大流。

這就是 FF 思想,也是一堆最大流演算法的根源。

2. EK

通過暴力找增廣路,然後加入殘留網路,這是 EK 的思想。

大概分為以下幾步:

  1. 通過 BFS 找到一條增廣路 \(f'\)
  2. 更新殘留網路,若對於一條邊 \((u,v)\) 流過了 \(k\) 的流量,那麼 \(\begin{cases}C(u,v)=C(u,v)-k\\C(v,u)=C(v,u)+k\end{cases}\)
  3. 需要減的流量為找到增廣路上最小的容量

肯定用鄰接表存圖,所以有一個小 trick : \(i\) 的反向邊為 \(i \oplus 1\)

時間複雜度不優,為 \(O(nm^2)\)

但是跑不滿\(10^3\)\(10^4\) 可跑。

最大流一般不用,但是費用流要用。

程式碼實現:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+5;
struct node
{
    int to,nxt,flow;
}e[MAXN];
int head[MAXN],cnt=1;//因為要異或得反向邊,cnt需從1開始
int n,m,s,t;
inline void add(int x,int y,int f)
{
    e[++cnt].to=y;
    e[cnt].flow=f;
    e[cnt].nxt=head[x];
    head[x]=cnt;
}
bitset<MAXN>vis;
int pre[MAXN],dis[MAXN];//pre記錄當前點是從哪條邊過來的,dis是當前點之前最小的容量
inline bool bfs()//bfs找一條增廣路
{
    vis=0;
    vis[s]=1;
    dis[s]=0x7f7f7f7f;
    queue<int>q;
    q.push(s);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(register int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to,f=e[i].flow;
            if(!vis[y]&&f)//若沒有經過且容量大於0,則可以成為增廣路的一部分
            {
                pre[y]=i;//直接記錄邊的編號
                dis[y]=min(dis[x],f);
                vis[y]=1;
                if(y==t)return true;//現在到了匯點,直接找到了
                q.push(y);
            }
        }
    }
    return false;
}
inline void EK()
{
    int ans=0;
    while(bfs())
    {
        ans+=dis[t];
        for(register int i=t;i!=s;i=e[pre[i]^1].to)//不斷遍歷直到訪問到源點
        {
            e[pre[i]].flow-=dis[t];//流過的邊容量要減
            e[pre[i]^1].flow+=dis[t];//小trick應用處
        }
    }
    printf("%d",ans);
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(register int i=1;i<=m;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
        add(y,x,0);//反向邊最初容量為0
    }
    EK();
    return 0;
}

3. dinic

時間複雜度較優,為 \(O(n^2m)\)

同樣跑不滿\(10^4\)\(10^5\) 可跑。

4. ISAP