推重标签算法 |第 1 套(介绍和插图)
给定一个表示流网络的图,其中每条边都有容量。同样给定图中的两个顶点source 's' 和sink 't',找到从 s 到 t 的最大可能流量,并具有以下约束: a)边上的流量不超过边的给定容量。 b)对于除 s 和 t 之外的每个顶点,流入流等于流出流。例如,考虑 CLRS 书中的下图。 上图中的最大可能流量为 23。 我们已经讨论了使用增广路径来计算最大流量的福特富尔克森算法。
Push-Relabel 方法比 Ford-Fulkerson 算法更有效。在这篇文章中,讨论了 Goldberg 的“通用”最大流量算法,该算法在O(V 2 E)时间内运行。该时间复杂度优于 O(E 2 V),后者是 Edmond-Karp 算法(Ford-Fulkerson 的基于 BFS 的实现)的时间复杂度。存在一种基于推送重新标记方法的算法,该算法在 O(V 3 ) 中工作,甚至比这里讨论的更好。与福特富尔克森的相似之处
- 与 Ford-Fulkerson 一样,Push-Relabel 也适用于 Residual Graph(流网络的 Residual Graph 是表示附加可能流的图。如果残差图中存在从源到汇的路径,则可以添加流) .
与福特富尔克森的区别
- Push-relabel 算法的工作方式更加本地化。 push-relabel 算法不是检查整个残差网络来寻找增广路径,而是一次在一个顶点上工作(来源:CLRS Book)。
- 在 Ford-Fulkerson 中,每个顶点(源和汇除外)的总流出量和总流入量之间的净差保持为 0。 Push-Relabel 算法允许流入量在达到最终流量之前超过流出量。在最终流程中,除源和汇之外的所有净差均为 0。
- 时间复杂度更有效。
push-relabel 算法背后的直觉(考虑流体流动问题)是我们将边缘视为水管,节点是关节。水源被认为是最高水位,它将水输送到所有相邻节点。一旦一个节点有多余的水,它就会把水推到一个更小的高度节点。如果水被局部困在一个顶点,该顶点被重新标记,这意味着它的高度增加了。以下是在我们进行算法之前需要考虑的一些有用的事实。
- 每个顶点都关联了一个高度变量和一个额外流量。高度用于确定顶点是否可以将流推到相邻的顶点(一个顶点只能将流推到高度较小的顶点)。过量流量是进入顶点的总流量减去离开顶点的总流量的差。
Excess Flow of u = Total Inflow to u -
Total Outflow from u
- 就像福特富尔克森一样。每条边都关联了一个流(表示当前流)和一个容量
以下是完整算法的抽象步骤。
Push-Relabel Algorithm
1) Initialize PreFlow : Initialize Flows
and Heights
2) While it is possible to perform a Push() or
Relabel() on a vertex
// Or while there is a vertex that has excess flow
Do Push() or Relabel()
// At this point all vertices have Excess Flow as 0 (Except source
// and sink)
3) Return flow.
Push-Relabel算法主要有3个操作
- Initialize PreFlow()它初始化所有顶点的高度和流。
Preflow()
1) Initialize height and flow of every vertex as 0.
2) Initialize height of source vertex equal to total
number of vertices in graph.
3) Initialize flow of every edge as 0.
4) For all vertices adjacent to source s, flow and
excess flow is equal to capacity initially.
- Push()用于从具有多余流量的节点产生流量。如果一个顶点有多余的流量并且有一个高度较小的相邻节点(在残差图中),我们将流量从顶点推到高度较低的相邻节点。通过管道(边缘)的推流量等于过量流量和边缘容量的最小值。
- Relabel()操作用于当一个顶点有多余的流量并且它的相邻顶点都没有处于较低高度时。我们基本上增加了顶点的高度,以便我们可以执行 push()。为了增加高度,我们选择最小高度相邻(在残差图中,即我们可以添加流量的相邻)并将其加 1。
请注意,上述操作是在残差图上执行的(如 Ford-Fulkerson)。说明:在进行下面的示例之前,我们需要确保我们了解残差图(有关残差图的更多详细信息,请参阅this)。残差图与显示的图不同。每当我们从顶点 u 向 v 推送或添加流时,我们都会在残差图中进行以下更新:1)我们从 u 到 v 的边的容量中减去流。如果边的容量变为 0,则边不再存在于残差图中。 2) 我们将流添加到从 v 到 u 的边的容量中。
For example, consider two vertices u an v.
In original graph
3/10
u ---------> v
3 is current flow from u to v and
10 is capacity of edge from u to v.
In residual Graph, there are two edges corresponding
to one edge shown above.
7
u ---------> v
3
u <--------- v
- 初始给定流程图。
- PreFlow 操作后。在残差图中,从 A 到 S 有一条容量为 3 的边,从 S 到 A 没有边。
- 突出显示的顶点被重新标记(高度变为 1),因为它有多余的流量并且没有具有较小高度的相邻。新的高度等于相邻高度的最小值加1。在残差图中,顶点A有两个相邻,一个是S,另一个是B。S的高度为4,B的高度为0。这两者的最小值高度为 0。我们取最小值并将其加 1。
- 突出显示的顶点有多余的流量,并且有一个高度较低的相邻顶点,所以 push() 发生了。顶点A的多余流量为2,边(A,B)的容量为1。因此,推流量为1(两个值的最小值)。
- 突出显示的顶点被重新标记(高度变为 1),因为它有多余的流量并且没有具有较小高度的相邻。
- 突出显示的顶点有多余的流量,并且有一个高度较低的相邻顶点,因此 flow() 从 B 推到 T。
- 突出显示的顶点被重新标记(高度变为 5),因为它有多余的流量并且没有具有较小高度的相邻。
- 突出显示的顶点有多余的流量,并且有一个高度较低的相邻顶点,所以 push() 发生了。
- 突出显示的顶点被重新标记(高度增加 1),因为它有多余的流量并且没有具有较小高度的相邻。