網絡流是一種生活中常見的圖模型,包含一個起始點,和一個匯點,以及若干結點,用有向邊連接,每條邊的權值代表能流經該邊的最大流量。生活中,水流網絡,電流網絡,信息網絡這些問題都能描述成網絡流。網絡流中一種常見的問題是最大流問題。即求從起始點到達匯點流的最大值。在《算法導論》介紹了Edmonds-Karp算法,該算法運行時間在圖G=(V,E)上爲O(VE),基於BFS實現。
實現過程是從殘存網絡中找到一條最短的增廣路徑,對路徑上的邊做增廣操作,並改變一些數據,直到殘存網絡中不在存在增廣路徑。
殘存網絡簡單來講就是在每次增加操作結束後得到的網絡,原本在網絡流中不允許出現平行反向的邊(若map[u][v]爲網絡流中的一條邊,那麼網絡流中必然不存在map[v][u],map[v][u]爲map[u][v]的平行反向邊,畫圖的話會很好理解)。但是在殘存網絡中需要加入反向平行邊(如果有必要)。每條邊的權值表示可通過該邊的流量,那麼在殘存網絡中,反向平行邊的權值代表的是原本已經流過該邊的流量。例如:f[u][v]=x代表已經流過該邊的流量,那麼,map[v][u]的權值就爲f[u][v]。可以看出,未做任何操作的流網絡也是一個殘存網絡。
增廣路徑就是在殘存網絡中可以從起始點走到匯點(想了一下,可能叫目標點會更好理解?)的一條簡單路徑。如圖,1-->2-->4-->6爲一條增廣路徑。
接下來就是每次找到增廣路徑以後對路徑上每條邊做處理了c[u][v]代表邊uàv的能通過的最大流量或者叫做容量。首先需要找到該路徑的增加流量,該流量值爲該路徑上所有邊中殘存流量的最小值,這是保證可以通過該路徑的最大流量值。接下來需要縮減通過該邊的容量,同時需要增加平行反向邊的容量。記增加流量爲p,那麼u-->v爲該路徑上的邊。c[u][v]-=p;c[v][u]+=p。
按照這樣的操作直到不存在增廣路徑。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int path[1000005],flow[1000005];
int map[1005][1005],que[1000005];
int n,m;
int BFS(int start,int des)
{
int head,tail;
memset(que,0,sizeof que);
for (int i=1;i<=n;i++)
{
path[i]=-1;
}
path[start]=0;
flow[start]=0x3f3f3f3f;
head=tail=0;
que[head++]=start;
while (head>tail)
{
int u=que[tail++];
if (u==des)
break;
for (int i=1;i<=n;i++)
{
if (i!=str&&path[i]==-1&&map[u][i]>0)
{
path[i]=u;
flow[i]=min(map[u][i],flow[u]);
que[head++]=i;
}
}
}
if (path[des]==-1)
return -1;
return flow[des];
}
int maxflow(int start,int des)
{
int sum=0,increase=0;
while ((increase=BFS(start,des))!=-1)
{
int k=des;
while (k!=start)
{
int pre=path[k];
map[pre][k]-=increase;
map[k][pre]+=increase;
k=pre;
}
sum+=increase;
}
return sum;
}
int main()
{
int start,end,f;
while (cin>>n>>m)
{
memset(map,0,sizeof map);
for (int i=0;i<m;i++)
{
cin>>start>>end>>f;
map[start][end]+=f;
}
cin>>start>>end;
int ans=maxflow(start,end);
cout<<ans<<endl;
}
}