福特-富尔克森算法

福特-富尔克森方法（），又称福特-富尔克森算法（），是一类计算网络流的最大流的贪心算法。之所以称之为“方法”而不是“算法”，是因为它寻找增广路径的方式并不是完全确定的，而是有几种不同时间复杂度的实现方式。它在1956年由小莱斯特·伦道夫·福特及德尔伯特·雷·富尔克森发表。“福特-富尔克森”这个名词通常也指代埃德蒙兹-卡普算法，这是一个特殊的福特-富尔克森算法实现。
算法的思想如下：只要有一条从源点（开始节点）到汇点（结束节点）的路径，在路径的所有边上都有可用容量，就沿着这条路径发送一个流，流量由路径上的最小容量限制。 然后再找到另一条路径，一直到网络中不存在这种路径为止。 一条有可用容量的路径被称为一条增广路径。
算法.
设formula_1为一个图，并且为每条从formula_2到formula_3的边formula_4设置一个最大流量formula_5，并且初始化当前流量formula_6。下面是该算法每一步的实现：
这意味着每轮计算之后通过网络的都是一个流。我们定义残留网络 formula_7是一个网络的剩余流量formula_8。注意残留网络可以设置从formula_3到formula_2的流量，即使在原先的网络中不允许这种情况产生：如果 formula_11 但 formula_12，那么formula_13：也即，从formula_2到formula_3的流量给从formula_3到formula_2的流量提供了额外的剩余量。
伪代码.
算法 福特-富尔克森
步骤2中的路径formula_33可以用广度优先搜索或深度优先搜索在formula_7中找到。如果使用了广度优先搜索，这个算法就是Edmonds–Karp算法。
当步骤2中找不到可行路径时，formula_20就无法在残留网络中到达formula_21。设formula_47是在残留网络中formula_20可以到达的节点的集合，然后从formula_47到formula_50的其余部分的网络一方面等于我们找到的从formula_20到formula_21的所有流的总流量，另一方面所有这样的流量组成了一个上限。这说明我们找到的流是最大的。参见最大流最小割定理。
如果图formula_1有多个源点和汇点，可以按如下方法处理：设formula_54，formula_55。 添加一个新源点formula_56与所有源点有一条边formula_57相连，容量formula_58。添加一个新汇点formula_59与所有汇点formula_60 有一条边相连，容量formula_61。然后执行福特-富尔克森算法。
同样的，如果节点formula_2有通过限制formula_63，可将这个节点用两个节点formula_64替换，用一条边formula_65相连，容量为formula_66。然后执行福特-富尔克森算法。
复杂度.
算法通过添加找到的增广路径的流量增加总流量，当无法找到增广路径时，总流量就达到了最大。当流量是整数时，福特-富尔克森算法的运行时间为formula_67（参见大O符号）, formula_68图中的边数，formula_25为最大流。 这是因为一条增广路径可以在formula_70的时间复杂度内找到，每轮算法执行后流量的增长至少为formula_71。但是在极端情况下，算法有可能永远不会停止。
福特-富尔克森算法的一个特例是埃德蒙兹-卡普算法，时间复杂度为formula_72。
样例.
下面的样例演示了福特-富尔克森在一张有4个节点，源点为formula_73，汇点为formula_74的图中的第一轮计算。 这个例子显示了算法在最坏情况下的行为。在每一轮算法中，只有formula_71的流量被发送至网络中。如果算法改用宽度优先搜索，那么只需要两轮计算。
注意当找到路径formula_76时，流是如何从formula_77发送至formula_78的。
无法终止算法的样例.
右图所示的网络中源点为formula_20，汇点为formula_21边formula_81、formula_82、formula_83的容量为formula_71, formula_85和formula_71，使formula_87。其它所有边的容量formula_88。 使用福特-富尔克森算法可找到三条增广路径，分别为formula_89、formula_90、formula_91.
注意在步骤1和步骤5之后,边formula_81、formula_82、formula_83的残留容量都可以表示为formula_95、formula_96或formula_97，同时，对于一些特殊的formula_98这意味着算法可以通过formula_99、formula_100、formula_99与 formula_102无限增广，并且残留容量总处于一个循环。在步骤5之后网络的流为formula_103，如果继续用以上的算法增广，总的流将向formula_104趋近，但最大流为formula_105。在这个样例中，算法将永远不会停止，且结果也不会向实际的最大流趋近。
Python源码.
class Edge(object):
 def __init__(self, u, v, w):
 self.source = u
 self.sink = v 
 self.capacity = w
 def __repr__(self):
 return "%s-&gt;%s:%s" % (self.source, self.sink, self.capacity)
class FlowNetwork(object):
 def __init__(self):
 def add_vertex(self, vertex):
 self.adj[vertex] = []
 def get_edges(self, v):
 return self.adj[v]
 def add_edge(self, u, v, w=0):
 if u == v:
 raise ValueError("u == v")
 edge = Edge(u,v,w)
 redge = Edge(v,u,0)
 edge.redge = redge
 redge.redge = edge
 self.adj[u].append(edge)
 self.adj[v].append(redge)
 self.flow[edge] = 0
 self.flow[redge] = 0
 def find_path(self, source, sink, path):
 if source == sink:
 return path
 for edge in self.get_edges(source):
 residual = edge.capacity - self.flow[edge]
 if residual &gt; 0 and edge not in path:
 result = self.find_path( edge.sink, sink, path + [edge]) 
 if result != None:
 return result
 def max_flow(self, source, sink):
 path = self.find_path(source, sink, [])
 while path != None:
 residuals = [edge.capacity - self.flow[edge] for edge in path]
 flow = min(residuals)
 for edge in path:
 self.flow[edge] += flow
 self.flow[edge.redge] -= flow
 path = self.find_path(source, sink, [])
 return sum(self.flow[edge] for edge in self.get_edges(source))
使用样例.
»&gt; g = FlowNetwork()
»&gt; [g.add_vertex(v) for v in "sopqrt"]
[None, None, None, None, None, None]
»&gt; g.add_edge('s','o',3)
»&gt; g.add_edge('s','p',3)
»&gt; g.add_edge('o','p',2)
»&gt; g.add_edge('o','q',3)
»&gt; g.add_edge('p','r',2)
»&gt; g.add_edge('r','t',3)
»&gt; g.add_edge('q','r',4)
»&gt; g.add_edge('q','t',2)
»&gt; print (g.max_flow('s','t'))
5
应用.
二分图的最大匹配
最大不相交路径