因為網上介紹網路流和最大流理論的文章非常的多,也都解釋的非常清晰並附帶**。再加上繪圖技術不佳,語文表達極差,就只講解一下程式實現部分。想看理論講解及演算法正確性證明的讀者可以上網搜一搜,這裡推薦一篇部落格,鏈結如下:
那麼,既然網上的資源那麼多,為什麼還要寫這篇部落格呢?一是為了湊數做筆記,二是網上的許多演算法模板都十分工程化,變數名賊長,**量巨大也不容易理解,在博主初學時帶來了不小麻煩。於是,本著能水一篇是一篇普度眾生的情懷,博主在這裡就講解一下,最大流的幾種演算法與自認為很簡潔的**。
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 代表運輸路徑,邊上的權值代表運輸容量限制,各個節點表示每乙個中轉點。每乙個運輸路線上運輸量不能超...