1.物理模型
请想象一组相互连接大小不一的输油管道,每根管道有它自己的流量和容量,问从起点到终点的最大流量是多少?如下流量图中,深色路径流量之和为最大路径。如何求得,下面内容将详细介绍。
2.数学模型
一个流量网络,是一张边的权重(这里称为容量)为正的加权有向图。一个st-流量网络有两个已知的顶点,即起点s和终点t。
3.Ford-Fulkerson算法
也称为增广路径算法。它的定义是:网络中的初始流量为零,沿着任意从起点到终点(且不含有饱和的正向边或是空逆向边)的增广路径增大流量,直到网络中不存在这样的路径为止。
也即,假设x为该路径上的所有边中未使用容量的最小值,那么只需将所有边的流量增大x,即可将网络中的总流量至少增大x。反复这个过程,直到所有起点到终点的路径上至少有一条边是饱和的。
4.剩余网络
这里,与流量对应的边的方向和流量本身相反。代码如下FlowNetwork类。
5.代码实现
对Ford-Fulkerson算法最简单的实现可能就是最短增广路径算法了(最短指的是路径长度最小,而非流量或是容量)。增广路径的查找等价于剩余网络中的广度优先搜索(BFS)。
public class FordFulkerson
{
private boolean[] marked; //在剩余网络中是否存在从s到v的路径
private FlowEdge[] edgeTo; //从s到v的最短路径上的最后一条边
private double value; //当前最大流量
public FordFulkerson(FlowNetwork G, int s, int t)
{ //找出从s到t的流量网络G的最大流量配置
while(hasAugmentingPath(G, s, t))
{ //利用所有存在的增广路径
//计算当前的瓶颈容量
double bottle = Double.POSITIVE_INFINITY;
for(int v = t; v != s; v = edgeTo[v].other(v))
{
bottle = Math.min(bottle, edgeTo[v].residualCapacityTo(v));
}
//增大流量
for(int v = t; v != s; v = edgeTo[v].other(v))
{
edgeTo[v].addResidualFlowTo(v, bottle);
}
value += bottle;
}
}
private boolean hasAugmentingPath(FlowNetwork G, int s, int t)
{
marked