最大流的问题描述可以对比参照水在水管中的流动。从源(图中唯一的入度为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;
}