一、网络流的定义
有向图 G = ( V, E )中:
•有唯一的一个源点S(入度为0:出发点)
•有唯一的一个汇点 T(出度为0:结束点)
•图中每条弧 (u, v) 都有一非负容量 c ( u, v )
满足上述条件的图G称为网络流图。
记为: G = ( V, E ,C)
1、可行流
◆每条弧 ( u, v )上 给定一个实数f(u,v),满足:有 0 <= f ( u, v ) <= c( u, v ),则f(u,v)称为弧( u, v )上的流量。
◆如果有一组流量满足条件:
源点s : 流出量 = 整个网络的流量
汇点t : 流入量 =整个网络的流量
中间点:总流入量 = 总流出量
那么整个网络中的流量成为一个可行流。
2、最大流
•在所有的可行流中, 流量最大的一个流的流量
如: 图2中可行流7也是最大流。
•最大流可能不只一个。
二、最大流算法
◆Ford-Fulkerson (福特-福克森)算法:
步骤:
(1)如果存在增广路径,就找出一条增广路径
(1)如果存在增广路径,就找出一条增广路径
(2)然后沿该条增广路径进行更新流量(增加流量)
1、增广路径
•从 s 到 t 的一条简单路径,若边 ( u, v ) 的方向与该路径的方向一致,称 ( u, v ) 为正向边,方向不一致时称为逆向边。
若路径上所有的边满足:
①所有正向边有:f ( u, v ) < c ( u, v)
②所有逆向边有:f ( u, v ) > 0
②所有逆向边有:f ( u, v ) > 0
则称该路径为一条增广路径(可增加流量)
2、沿增广路径增广
1) 先设d为为正无穷(可增加流,余流量)
若( u, v ) 是正向边
d = min ( d, c ( u, v ) – f (u, v ) )
若( u, v ) 是逆向边
d = min ( d, f ( u, v ) )
2) 对与该增广路径上的边
若( u, v ) 是正向边,f ( u, v ) = f ( u, v ) + d;
若( u, v ) 是逆向边,f ( u, v ) = f ( u, v ) – d;
增广后,总流量增加了d
•定理:
可行流 f 为最大流,当且仅当不存在关于f 的增广路径
证:若 f 是最大流,但图中存在关于 f 的增广路径,则可以沿该增广路径增广,得到的是一个更大的流,与f 是最大流矛盾。所以,最大流不存在增广路径。
◆Ford-Fulkerson方法(增广流)求最大流
(福特-福克森)
(福特-福克森)
步骤:
(1)如果存在增广路径,就找出一条增广路径
(1)如果存在增广路径,就找出一条增广路径
DFS,BFS
(2)然后沿该条增广路径进行更新流量
(2)然后沿该条增广路径进行更新流量
(增加流量)
While 有增广路径 do 更新该路径的流量
迭代算法
算法的实现:
c [ u, v ]:容量
f [ u, v ]:流量
B[i]:保存找到的增广路径,记录路径上结点i的前驱结点。
Sum:最大流量。
假定:1是源点S;n是汇点T。
#include <iostream>
#include <algorithm>
#include <cstring>
#define OO 999999
using namespace std;
int c[100][100];//容量
int f[100][100];//流量
int b[100]; //增广路径前驱结点
int sum;
int n,m;
bool findflow(int k);
void addflow();
//找到k节点的后继节点i
bool findflow(int k)
{
if (k==n) return true;//找到了一条增广路径
for (int i=1;i<=n;i++)
{
if ( b[i]==-1 && (c[k][i]-f[k][i]>0||f[i][k]>0) )
{
b[i]=k;
if ( findflow(i) ) return true;
}
}
return false;
}
//沿增广路径增广
void addflow()
{
int d=OO;
int i=n;
while ( b[i]!=0 )
{
if ( c[b[i]][i]>0 )
{
d=min(d,c[b[i]][i]-f[b[i]][i]);
}
if ( c[i][b[i]]>0 )
{
d=min(d,f[i][b[i]]);
}
i=b[i];
}
i=n;
while ( b[i]!=0 )
{
if ( c[b[i]][i]>0 )
{
f[b[i]][i]+=d;
}
if ( c[i][b[i]]>0 )
{
f[i][b[i]]-=d;
}
i=b[i];
}
sum+=d;
}
int main()
{
int x,y,z;
cin >> n >> m;
memset(c,-1,sizeof(c));
memset(f,0,sizeof(f));
for (int i=1;i<=m;i++)
{
cin >> x >> y >> z;
c[x][y]=z;
}
for (int i=0;i<=n;i++) b[i]=-1;
b[1]=0;
while ( findflow(1) )
{
addflow();
for (int i=0;i<=n;i++) b[i]=-1;
b[1]=0;
}
cout << sum << endl;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
{
if (f[i][j]>0) cout << i << "-->" << j << " " << f[i][j] << endl;
}
}
return 0;
}