Ford-Fulkerson算法
Ford-Fulkerson算法是一种解决最大流min-cut问题。也就是说,给定一个网络,它有一些顶点和这些顶点之间的边,这些顶点之间有一定的权值,网络一次能处理多少“流量”?流可以是任何东西,但通常是指通过计算机网络的数据。
它是由福特和富尔克森于1956年发现的。这种算法有时称为方法,因为它的协议的某些部分没有完全指定,并且可以从实施实现而变化。算法典型地指的是用于解决问题的特定协议,而方法是有问题的更一般的方法。
Ford-Fulkerson算法假设输入是图形那 连同源顶点, ,和汇聚顶点, .图是一个加权图的任何表示,其中顶点由指定权值的边连接。还必须有一个源顶点和汇聚顶点来理解流网络的起点和终点。
Ford-Fulkerson具有复杂性 在哪里 为网络的最大流量。福特-福克森算法最终被Edmonds-Karp算法,它做同样的事情在 时间,与最大流量无关。
直觉
算法背后的直觉非常简单(即使实施细节也可以遮挡这一点)。想象一下只是汽车的流量网络。每条道路都可以持有一定数量的汽车。这可以通过以下图形说明。
直觉就是这样的:只要有一个路径从源到水槽可以采取一些流量的整个方式,我们发送它。这条路径被称为增广路径.直到有没有更多的增广路径我们一直在这样做。在上图中,我们可以通过发送2台车沿最顶端的路径(因为只有2辆可以通过最后一部分得到)开始。然后,我们可能会发送3辆汽车沿着底部路径共5辆。最后,我们可以发送沿着顶部路径2路车多了两个边,把他们下到底层路径,并通过与水槽。送车的总数现在是7,这是最大流量。
为什么在前面的例子中,我们只能在最后的增强路径中发送2辆车?
我们已经沿着顶级派了两辆汽车的第一个增强路径。这意味着沿着该顶级路径的前两个边缘已经存在 容量。因此,这些边缘不适合任何超过2辆车,所以他们在过去的增广路径的限制因素。这就是为什么计算增强路径对于较大和更复杂的流量网络变得棘手。处理这个,剩余图在找到每个增广路径并使其最大化后生成。残差图显示了不同路径的容量和它们当前的流量之间的差异,并允许未来增加路径的精确计算。
算法伪代码
这个方法的伪代码非常短;然而,有一些功能需要进一步讨论。下面是简单的伪代码。
这种伪代码不是写在任何特定的计算机语言。相反,它是算法的非正式高级别描述。
Ford-Fulkerson算法 图 , 来源 , 下沉
1 2 3 4 5 6 7 |
|
基本上,这个简化的版本说的是,只要有从源到水槽的路径可以处理更多流量,就会发送该流程。以下是伪代码的版本,用于更深入地解释流量增强:
12 3 4 5 6 7 8 9 10 11 12 |
|
该算法是比较明确的。唯一的不明确的一点是在线路8.“FOWARD边缘”术语当一个剩余图, ,则可以创建与原始图相反方向的边。如果一条边在原始图中存在,那么它就是一条“前边”, .如果它是一个原始边缘的反转,它被称为“向后边缘”。
残余图形
残余图是计算最大流量的重要中间步骤。如上所述伪代码,每一步都要计算它们,这样就可以找到从源到汇的增广路径。为了理解它们是如何创建和使用的,我们可以使用直觉部分。
然而,在查看残差图之前,有一个重要的属性是必须理解的。剩余容量是在上述伪代码中使用的术语,它在剩余图形创建中发挥着重要作用。在给定流量被带走后,剩余容量被定义为新容量。换句话说,对于给定的边缘 ,剩余容量, 被定义为
但是,也必须有一个剩余的能力逆转边缘。这最大流最小割定理流的状态必须保存在网络中。所以,下面的等式总是成立的:
有了这些工具,就有可能计算出流动网络中任何边(向前或向后)的剩余容量。然后,利用这些剩余容量构造剩余网络, .
采用原始的直觉网络并向顶点添加标签,我们现在有这个:
结果表明,2个单位的流动可沿最上面的路径首先被推动。当发生这种情况,只有三个边缘受到影响:(S,A),(A,B),和(B,T)。(S,A)和(A,B)以相同的方式受到影响,因为它们具有相同的容量。两件事情:
- 朝前方向,则边的剩余容量为 .流程等于2,因此(S,a)和(a,b)的剩余容量减小到2,而边缘(b,t)的剩余容量为0。
- 反向,则边的剩余容量为 .由于流量保存,这可以写成 .由于这些后向边的容量最初是0,所有后向边(T, B) (B, A)和(A, S)的剩余容量都是2。
当用这些新边构造一个新的残差图时,不包括任何具有类0 (B, T)残差容量的边。
现在,必须找到一条新的增强路径 最上面的路径不能被再次使用,因为边缘(B,T)被抹掉 可以选择底部路径,并沿其发送3条流。得到的曲线图如下:
最后,为2的流动可沿路径发送[(S,A),(A,B),(B,C),(C,d),(d,T)],因为沿着最小剩余容量路径是2。在此之后完成最后的剩余图如下:
没有更多的路径从源头到水槽,所以不能有更多的扩展路径。因此,循环完成。流量,7,是最大流量。
Python实现示例
福特-Fulkerson算法是直接实现一次的概念剩余图据了解。如上所述,该算法通常称为方法,因为未完全指定在残余图中找到增强路径的方法。这种实现是这样做的一种方式。
下面的实现是不经过实战检验,并且只意味着是一个学习工具.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 5051 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100101 102 103 |
|
在线定义的类1
是一个简单的顶点
班级。它只有一个名称,我们用于边缘创建(和调试),无论顶点是否是源或宿者。在线的7.
, 这边缘
类是定义的。此类具有起始顶点(仅仅是顶点的名称,而不是类实例),结束顶点,容量,流量,以及在残差图中使用的返回边缘的指针。边缘的容量是它的总重量可以进而边缘的流动是它是重目前携带。
这flownetwork.
在线定义类15
有两个属性。这顶点
属性是图表中顶点所有实例的列表。此列表包含整个对象,将顶点的名称链接到其源和宿属性。这网络
字典是一种数据结构,每个顶点的名称映射到未来所有相应的顶点出了边线。通过简单地具有顶点的名字充当字典的键,我们可以轻松地来回切换“顶点”和“网络”之间,以适应算法的需求。
线20-48
含有各种辅助功能,使后来的功能更容易,帮助减少代码的重复。例如,上线功能32
那getVertex ()
取一个顶点名,然后去找整个顶点
对象flownetwork.
的顶点
属性。
addVertex()
在线的50
增加了一个顶点到图中它检查后各种错误情况,以确保可以加入顶点。它增加了整个顶点到顶点
在一行62.
并将顶点名称添加到一个空的线上边列表中63.
.添加()
在线的65.
首先检查起始顶点和结束顶点都在图中,并且它们不是同一个顶点。然后,它创建新的边和相应的返回边,容量为0。然后,它将新的边缘在线添加到网络地图中77.
并在线添加返回边缘到同一地图79.
.
在“的getPath()”上线功能81.
做这门课上重要的工作。这是一个递归功能通过在给定顶点开始的流量网络散步,并计算每个边缘的剩余容量。这种剩余容量用于决定沿着下一个功能中的给定路径发送多少流。将路径生长,直到它到达流量网络的末端;此时递归的基本情况在线调用82.
函数结束。
calculateMaxFlow ()
在线的91.
是什么电话getpath.
使用正确的参数并增加最大流量。它首先找到网络的源头和汇。然后,它计算行上的初始增强路径96.
.然后,我们开始了重要的福特Fulkerson增法,并继续计算流量,同时还有一个路径。虽然是一个路径,可增广容量是在路径的每个边缘,因此流可在线计算出98.
.该流程被添加到前边缘并从反向边缘中减去。然后,计算另一条路径并恢复过程。最后,我们只需要计算出来的总流量,因为这是通过整个网络的精确流量(因为我们只有一个来源)。
使用实现
说明以上Python实现,我们可以从中构建完全相同的图表直觉部分。
1 2 3 4 5 6 7 8 9 10 11 |
|
流动网络被创建,所以它顶点
和网络
可以检查。但是,这些属性包含完整的对象—顶点
属性包含顶点
对象和网络
属性包含边缘
对象。因此,我们需要把它清理干净一点。
1 2 3 4 |
|
记住,边缘是向内的getedges()
还包含了所有的反向边。现在,这个类可以计算出自己的最大流量。
1 2 |
|
这是我们发现早期检查相同的答案。
当'fn.calculateMaxFlow()'被调用时,'getEdges()'中的边的'capacity'和'flow'属性会发生什么?
提示:这回答向前边和向后边有一点不同。
一旦这个过程完成,所有的前边都尽可能地填满,而反向边则反映出填满的状态。随着最大流最小割定理状态,网络的总流量必须保留。因此,对于与端点给定边 ,前向和后向边的流量将总和为0,就像过程开始时一样。这里是调用前和调用后的区别
fn.calculateMaxFlow ()
:
1 2 3 4 5 6>>>['%S.->%S.;%S./%S.'%(E..开始那E..结尾那E..流那E..容量)为了E.在FN..阁()][“一 - > S;-4/0'那'a - > b;4/4'那'c - > s;-3/0'那“c - > d;5/6'那'c - > b;-2/0'那“B - >一个;-4/0'那“b - > t;2/2的那“b - c >;2/3的那' d - > c;-5/0'那'd - > t;5/6'那's - > a;4/4'那's - > c;3/3'那“t - > b;-2/0'那“T - > d;-5/0']>>>FN..calculatemaxflow.()7.>>>['%S.->%S.;%S./%S.'%(E..开始那E..结尾那E..流那E..容量)为了E.在FN..阁()][“一 - > S;-4/0'那'a - > b;4/4'那'c - > s;-3/0'那“c - > d;5/6'那'c - > b;-2/0'那“B - >一个;-4/0'那“b - > t;2/2的那“b - c >;2/3的那' d - > c;-5/0'那'd - > t;5/6'那's - > a;4/4'那's - > c;3/3'那“t - > b;-2/0'那“T - > d;-5/0']
如果你画出所有的边,你会看到你创建的图形和剩余图部分。
复杂
Ford-Fulkerson的分析很大程度上依赖于如何找到增广路径。典型的方法是使用广度优先搜索寻找路径。如果使用这种方法,福特富尔克森运行在多项式时间。
如果所有流都是整数,那么福特-Fulkerson的while循环最多运行 次, 为最大流量。这是因为流程在每次迭代中最多增加1。
查找增广路径中while循环需要 在哪里 是该组中的残余图中的边。这可以简化为 .因此,福特富尔克森的运行时间