#define MAX 201
#define Inf 1<<20
#define MIN(x,y) ((x) < (y) ? (x) : (y))
//-------------------------------------------------------
//总结:利用队列进行广度探索,标记每个点的父结点和可再容纳的最大流量,
//探测到汇点时,汇点的可再容纳流量即是增益的流量,
//反复进行,直到不能探测到汇点为止。
//-------------------------------------------------------
//参数:节点数n,矩阵mat[][],源点source,汇点sink,每条边的流量 flow[][]
//返回:最大流 每条边的流量flow
int ford_fulkerson(int n,int mat[][MAX],int source,int sink,int flow[][MAX])
{
//d[]用来表示还能容纳的容量
int pre[MAX],que[MAX],d[MAX],p,q,t,i,j;
//源点和汇点相同则返回
if (source==sink)
return Inf;
//初始化每条边的流量
for (i=0;i<n;i++)
for (j=0;j<n;j++)
flow[i][j] = 0;
//反复标记,反复查找增益路径
while(1)
{
//pre用来标记父结点,前驱节点,标记为0表示还为找到前驱节点
for (i=0;i<n;i++)
pre[i]=0;
t= source;
pre[source]=source+1;
d[source]=Inf;
//广度探索 que是用数组模拟的队列
for (p=q=0;p<=q && !pre[sink];t=que[p++])
{
for (i=0;i<n;i++)
{
//前向边
if (!pre[i] && mat[t][i]-flow[t][i] > 0){
//i加入队列
que[q++] = i;
//标记第i + 1个顶点的前驱为第t + 1个顶点
pre[i]=t+1;
d[i] = MIN(d[t],mat[t][i] - flow[t][i]);
}
//后向边
else if (!pre[i] && (j=flow[i][t]) > 0){
que[q++]=i;
//第i + 1个顶点的前驱为第t + 1个顶点,因为是后向边,加上-标记,整个成负数
pre[i]=-t-1;
d[i] = MIN(d[t],flow[i][t]);
}
}
}
//结束,不能标记汇点,也就是说不存在该条路径
if (!pre[sink]) break;
//回溯。。。
//从汇点开始增加边的流量,直到源点
for (i=sink;i!=source;)
{
//正向边
if (pre[i] > 0){
flow[pre[i]-1][i] += d[sink];
i=pre[i]-1;
}
//反向边
else{
flow[i][-pre[i]-1] -= d[sink];
i=-pre[i]-1;
}
}
}
//把和源点相接的边的流量相加即最大流量
j = 0;
for (i=0;i<n;i++)
j+=flow[source][i];
return j;
}
本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/GoOnDrift/archive/2010/08/23/5832666.aspx