網路流之最大流

2021-08-11 07:13:25 字數 3895 閱讀 8774

因為網上介紹網路流和最大流理論的文章非常的多,也都解釋的非常清晰並附帶**。再加上繪圖技術不佳,語文表達極差,就只講解一下程式實現部分。想看理論講解及演算法正確性證明的讀者可以上網搜一搜,這裡推薦一篇部落格,鏈結如下:

那麼,既然網上的資源那麼多,為什麼還要寫這篇部落格呢?一是為了湊數做筆記,二是網上的許多演算法模板都十分工程化,變數名賊長,**量巨大也不容易理解,在博主初學時帶來了不小麻煩。於是,本著能水一篇是一篇普度眾生的情懷,博主在這裡就講解一下,最大流的幾種演算法與自認為很簡潔的**。

1.ford-fulkerson(二f)演算法

因為本演算法博主並沒有學比較簡單且時間複雜度極高,基本被演算法競賽淘汰了,故不多作講解,感興趣的讀者請自行搜尋。

2.edmonds-karp(ek)演算法

輸入輸出樣例

輸入樣例#1:

5 a b 3

b c 3

c d 5

d z 4

b z 6

輸出樣例#1:

3 反正這個題只是讓大家檢驗一下自己編的演算法正確性的,博主直接上**,本篇部落格的重點放在下乙個演算法,**如下:

#include

using namespace std;

ints

q[300][300];//存圖

int flow[300];//存流量

int pre[300];//記錄增廣路路徑

int n;

queuedui;//bfs佇列

int bfs(int

s,int e)//bfs尋找增廣路

for(int i=1;i<=60;i++)

pre[s]=0;

flow[s]=1e9;

dui.push(s);

while(!dui.empty())

for(int i=1;i<=60;i++)}}

if(pre[e]==-1)

return flow[e];//返回最小流量

}int maxf(int

s,int e)

sum+=in;//記錄流量

in=bfs(s,e);

}return sum;

}int main()

printf("%d",maxf(1,26));

return

0;}

就這樣把兩個演算法水過了,相信大家一定受益匪淺,那麼接下來就進入本篇部落格的重點。

3.dinic演算法

輸入輸出樣例

輸入樣例#1:

4 5 4 3

4 2 30

4 3 20

2 3 20

2 1 30

1 3 40

輸出樣例#1:

50 dinic演算法的主要優化,就是加了乙個bfs分層,將網路分成多個層次,每次dfs尋找增廣路時都只搜尋下一層,返回的時候修改殘量網路裡的值。

定義結構體/陣列如下

const

int inf=0x3f3f3f3f;

const

int maxn=1e6+5;

struct edge;

edge ed[maxn<<1];//儲存邊,注意要開兩倍大小

int g=0;//記錄邊的數量,只在加邊的時候有用

vector

sq[maxn];//儲存已該為起點的邊的編號

這個結構體只用維護兩個量,相較網上的其他結構體比較簡單。

接下來是加邊的函式,**如下:

void add(int

x,int

y,int a)

;//相當於將乙個fl=a,to=y的edge型別變數放進ed陣列

sq[x].push_back(g++);//將這個邊的編號push進去

ed[g]=(edge);

sq[y].push_back(g++);//同上

}

到目前為止,dinic都十分簡單,接下來是bfs分層函式,跟普通的bfs相比只改動了一點,應該也很好懂,上**,詳細講解見注釋:

int d[maxn];

bool bfs(int s,int e)//s起點,e終點

d[to]=d[lo]+1;

dui.push(to);//普通的bfs}}

return d[e];//返回終點的層數,沒有標記過就會返回false,其他都是true

}

跟普通bfs完全只有一行**有區別對吧,相信大家依然活力十足,想要繼續讀完這篇部落格(手動滑稽),接下來就是dfs找增廣路了。

int dfs(int

s,int e,int minn)//s起點,e終點,minn記錄增廣的值

int ans=0;

for(int i=s

q[s].size()-1;i>=0;i--)

int tmp=dfs(to,e,min(minn-ans,fl));//遞迴搜尋

if(!tmp)//如果返回值已經為0,直接進入下乙個遞迴,不再回溯

ed[hh].fl-=tmp;

ed[hh^1].fl+=tmp;//修改邊的流

ans+=tmp;//記錄增廣的值

}return ans;

}

dinic的主要函式都已經講的差不多了,依然非常的簡單,最後來個dinic函式解決戰鬥

int dinic(int s,int e)

return ans;

}

在最最最後,貼上博主自認為簡潔的**,方便大家複製。

#include

using namespace std;

const int inf=0x3f3f3f3f;

const int maxn=1e6+5;

struct edge;

edge ed [maxn<<1];

vectors

q[maxn];

int g=0;

void add(int

x,int

y,int a)

; s

q[x].push_back(g++);

ed[g]=(edge);

sq[y].push_back(g++);

}int d[maxn];

bool bfs(int

s,int e)

d[to]=d[lo]+1;

dui.push(to);}}

return d[e];

}int dfs(int

s,int e,int minn)

int ans=0;

for(int i=s

q[s].size()-1;i>=0;i--)

int tmp=dfs(to,e,min(minn-ans,fl));

if(!tmp)

ed[hh].fl-=tmp;

ed[hh^1].fl+=tmp;

ans+=tmp;

}return ans;

}int dinic(int

s,int e)

return ans;

}int main()

printf("%d",dinic(s,e));

return

0;}

網路流之最大流

網路流之最大流 一 問題引入。有n個排水口,不同的排水口之間有m條水管連線,水一開始從源點s流出,最終到達t。每條邊 水管 都有乙個最大的流量。除了s,t外,每個排水口的流入量都要等於流出量,詢問最多能有多少水到達終點t 如圖所示 即poj 1273 可以將問題進行如下整理 1 用c e 表示每條邊...

網路流之 最大流

最大流演算法是網路流中基礎的演算法,解決的方法有很多,比如ek,dinic,sap等等,在這裡介紹一下ek演算法。從源點s開始廣度優先尋找一條到t的路徑,計算出這條路徑的最大流量 短板效應 l,回溯,將這條路徑的每條邊的最大流量減去l,然後新增反向邊,容量為l,網路流的最大流max l。當找不到從s...

網路流之最大流

通俗易懂的說就是從乙個起點運輸貨物到終點,但是途中運輸的容量有各自不同的限制,有大有小,起點和終點分別用s,t表示,其中有中轉點,運輸路線和運輸容量。用圖論中的有向圖中g v,e 來表示,每條邊 u,v 代表運輸路徑,邊上的權值代表運輸容量限制,各個節點表示每乙個中轉點。每乙個運輸路線上運輸量不能超...