最大流的問題描述可以對比參照水在水管中的流動。從源(圖中唯一的入度爲0的點)流到匯(圖中唯一出度爲0的點)。每條水管都有限定的容量,要求最多能有“多少”水同時流動到匯。
最大流的一種比較優的解法時Edmonds-Karp算法,不斷找一條源到匯的路徑,若有,找出增廣路徑上每一段[容量-流量]的最小值delta,然後構建殘餘網絡,再在殘餘網絡上尋找新的路徑,增加總流量,形成新的殘餘網絡,再尋找新路徑…..直到某個殘餘網絡上找不到從源到匯的路徑爲止,最大流就算出來了。通俗來說,當我們通過搜索找到一條從起點(源)到終點(匯)的路徑後,我們把路徑上每條正向邊都減掉算出來的流量值,同時反向邊加上算出來的流量值,然後再次搜索找新的路徑直到沒有辦法找到,每次都加上搜索出來的流量值即可。
附上代碼:
#include <iostream>
#include <queue>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
using namespace std;
#define arraysize 201
int maxData = 0x7fffffff;
int capacity[arraysize][arraysize]; //記錄殘留網絡的容量
int flow[arraysize]; //標記流動到當前節點後還有多少流量可以流動
int pre[arraysize]; //標記在這條路徑上當前節點的前驅,同時標記該節點是否在隊列中
int n,m;
queue<int> Q;
int BFS(int s,int t)
{
while(!Q.empty()) //隊列清空
Q.pop();
for(int i=1;i<m+1;++i)
pre[i]=-1;
pre[s]=0;
flow[s]= maxData;
Q.push(s);
while(!Q.empty())
{
int index = Q.front();
Q.pop();
if(index == t) //找到了增廣路徑
break;
for(i=1;i<m+1;++i)
{
if(i!=s && capacity[index][i]>0 && pre[i]==-1)
{
pre[i] = index; //記錄前驅
flow[i] = min(capacity[index][i],flow[index]); //關鍵:迭代的找到增量
Q.push(i);
}
}
}
if(pre[t]==-1) //殘留圖中不再存在增廣路徑
return -1;
return flow[t];
}
int maxFlow(int s,int t)
{
int incr= 0;
int sum= 0;
while((incr=BFS(s,t))!=-1)
{
int k = t; //利用前驅尋找路徑
while(k!=s)
{
int last = pre[k];
capacity[last][k] -= incr; //改變正向邊的容量
capacity[k][last] += incr; //改變反向邊的容量
k = last;
}
sum += incr;
}
return sum;
}