• Ford-Fulkerson 最大流算法


    流网络(Flow Networks)指的是一个有向图 G = (V, E),其中每条边 (u, v) ∈ E 均有一非负容量 c(u, v) ≥ 0。如果 (u, v) ∉ E 则可以规定 c(u, v) = 0。流网络中有两个特殊的顶点:源点 s (source)和汇点 t(sink)。为方便起见,假定每个顶点均处于从源点到汇点的某条路径上,就是说,对每个顶点 v ∈ E,存在一条路径 s --> v --> t。因此,图 G 为连通图,且 |E| ≥ |V| - 1。

    下图展示了一个流网络实例。

    设 G = (V, E) 是一个流网络,其容量函数为 c。设 s 为网络的源点,t 为汇点。G 的流的一个实值函数 f:V×V → R,且满足下列三个性质:

    • 容量限制(Capacity Constraint):对所有顶点对 u, v ∈ V,要求 f(u, v) ≤ c(u, v)。
    • 反对称性(Skew Symmetry):对所有顶点对 u, v ∈ V,要求 f(u, v) = - f(v, u)。
    • 流守恒性(Flow Conservation):对所有顶点对 u ∈ V - {s, t},要求 Σv∈Vf(u, v) = 0。

    f(u, v) 称为从顶点 u 到顶点 v 的流,流的值定义为:|f| =Σv∈Vf(s, v),即从源点 s 出发的总流。

    最大流问题(Maximum-flow problem)中,给出源点 s 和汇点 t 的流网络 G,希望找出从 s 到 t 的最大值流。

    满足流网络的性质的实际上定义了问题的限制:

    • 经过边的流不能超过边的容量;
    • 除了源点 s 和汇点 t,对于其它所有顶点,流入量与流出量要相等;

    上面的图中描述的流网络可简化为下图,其中源点 s = 0,汇点 t = 5。

    上图的最大流为 23,流向如下图所示。

    Ford-Fulkerson 算法是一种解决最大流的方法,其依赖于三种重要思想:

    1. 残留网络(Residual networks)
    2. 增广路径(Augmenting paths)
    3. 割(Cut)

    这些思想是最大流最小割定理的精髓,该定理用流网络的割来描述最大流的值。

    最大流最小割定理

    如果 f 是具有源点 s 和汇点 t 的流网络 G = (V, E) 中的一个流,则下列条件是等价的:

    1. f 是 G 的一个最大流。
    2. 残留网络 Gf 不包含增广路径。
    3. 对 G 的某个割 (S, T),有 |f| = c(S, T)。

    Ford-Fulkerson 算法是一种迭代方法。开始时,对所有 u, v ∈ V 有 f(u, v) = 0,即初始状态时流的值为 0。在每次迭代中,可通过寻找一条增广路径来增加流值。增广路径可以看做是从源点 s 到汇点 t 之间的一条路径,沿该路径可以压入更多的流,从而增加流的值。反复进行这一过程,直至增广路径都被找出为止。最大流最小割定理将说明在算法终止时,这一过程可产生出最大流。

    1 FORD-FULKERSON-METHOD(G, s, t)
    2   initialize flow f to 0
    3   while there exists an augmenting path p
    4     do augment flow f along p
    5   return f

    上述伪码实现的时间复杂度为 O(max_flow * E)。

    C# 代码实现如下:

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 
      5 namespace GraphAlgorithmTesting
      6 {
      7   class Program
      8   {
      9     static void Main(string[] args)
     10     {
     11       Graph g = new Graph(6);
     12       g.AddEdge(0, 1, 16);
     13       g.AddEdge(0, 2, 13);
     14       g.AddEdge(1, 2, 10);
     15       g.AddEdge(1, 3, 12);
     16       g.AddEdge(2, 1, 4);
     17       g.AddEdge(2, 4, 14);
     18       g.AddEdge(3, 2, 9);
     19       g.AddEdge(3, 5, 20);
     20       g.AddEdge(4, 3, 7);
     21       g.AddEdge(4, 5, 4);
     22 
     23       Console.WriteLine();
     24       Console.WriteLine("Graph Vertex Count : {0}", g.VertexCount);
     25       Console.WriteLine("Graph Edge Count : {0}", g.EdgeCount);
     26       Console.WriteLine();
     27 
     28       int maxFlow = g.FordFulkerson(0, 5);
     29       Console.WriteLine("The Max Flow is : {0}", maxFlow);
     30 
     31       Console.ReadKey();
     32     }
     33 
     34     class Edge
     35     {
     36       public Edge(int begin, int end, int weight)
     37       {
     38         this.Begin = begin;
     39         this.End = end;
     40         this.Weight = weight;
     41       }
     42 
     43       public int Begin { get; private set; }
     44       public int End { get; private set; }
     45       public int Weight { get; private set; }
     46 
     47       public override string ToString()
     48       {
     49         return string.Format(
     50           "Begin[{0}], End[{1}], Weight[{2}]",
     51           Begin, End, Weight);
     52       }
     53     }
     54 
     55     class Graph
     56     {
     57       private Dictionary<int, List<Edge>> _adjacentEdges
     58         = new Dictionary<int, List<Edge>>();
     59 
     60       public Graph(int vertexCount)
     61       {
     62         this.VertexCount = vertexCount;
     63       }
     64 
     65       public int VertexCount { get; private set; }
     66 
     67       public IEnumerable<int> Vertices
     68       {
     69         get
     70         {
     71           return _adjacentEdges.Keys;
     72         }
     73       }
     74 
     75       public IEnumerable<Edge> Edges
     76       {
     77         get
     78         {
     79           return _adjacentEdges.Values.SelectMany(e => e);
     80         }
     81       }
     82 
     83       public int EdgeCount
     84       {
     85         get
     86         {
     87           return this.Edges.Count();
     88         }
     89       }
     90 
     91       public void AddEdge(int begin, int end, int weight)
     92       {
     93         if (!_adjacentEdges.ContainsKey(begin))
     94         {
     95           var edges = new List<Edge>();
     96           _adjacentEdges.Add(begin, edges);
     97         }
     98 
     99         _adjacentEdges[begin].Add(new Edge(begin, end, weight));
    100       }
    101 
    102       public int FordFulkerson(int s, int t)
    103       {
    104         int u, v;
    105 
    106         // Create a residual graph and fill the residual graph with
    107         // given capacities in the original graph as residual capacities
    108         // in residual graph
    109         int[,] residual = new int[VertexCount, VertexCount];
    110 
    111         // Residual graph where rGraph[i,j] indicates 
    112         // residual capacity of edge from i to j (if there
    113         // is an edge. If rGraph[i,j] is 0, then there is not) 
    114         for (u = 0; u < VertexCount; u++)
    115           for (v = 0; v < VertexCount; v++)
    116             residual[u, v] = 0;
    117         foreach (var edge in this.Edges)
    118         {
    119           residual[edge.Begin, edge.End] = edge.Weight;
    120         }
    121 
    122         // This array is filled by BFS and to store path
    123         int[] parent = new int[VertexCount];
    124 
    125         // There is no flow initially
    126         int maxFlow = 0;
    127 
    128         // Augment the flow while there is path from source to sink
    129         while (BFS(residual, s, t, parent))
    130         {
    131           // Find minimum residual capacity of the edhes along the
    132           // path filled by BFS. Or we can say find the maximum flow
    133           // through the path found.
    134           int pathFlow = int.MaxValue;
    135           for (v = t; v != s; v = parent[v])
    136           {
    137             u = parent[v];
    138             pathFlow = pathFlow < residual[u, v]
    139               ? pathFlow : residual[u, v];
    140           }
    141 
    142           // update residual capacities of the edges and reverse edges
    143           // along the path
    144           for (v = t; v != s; v = parent[v])
    145           {
    146             u = parent[v];
    147             residual[u, v] -= pathFlow;
    148             residual[v, u] += pathFlow;
    149           }
    150 
    151           // Add path flow to overall flow
    152           maxFlow += pathFlow;
    153         }
    154 
    155         // Return the overall flow
    156         return maxFlow;
    157       }
    158 
    159       // Returns true if there is a path from source 's' to sink 't' in
    160       // residual graph. Also fills parent[] to store the path.
    161       private bool BFS(int[,] residual, int s, int t, int[] parent)
    162       {
    163         bool[] visited = new bool[VertexCount];
    164         for (int i = 0; i < visited.Length; i++)
    165         {
    166           visited[i] = false;
    167         }
    168 
    169         Queue<int> q = new Queue<int>();
    170 
    171         visited[s] = true;
    172         q.Enqueue(s);
    173         parent[s] = -1;
    174 
    175         // standard BFS loop
    176         while (q.Count > 0)
    177         {
    178           int u = q.Dequeue();
    179 
    180           for (int v = 0; v < VertexCount; v++)
    181           {
    182             if (!visited[v]
    183               && residual[u, v] > 0)
    184             {
    185               q.Enqueue(v);
    186               visited[v] = true;
    187               parent[v] = u;
    188             }
    189           }
    190         }
    191 
    192         // If we reached sink in BFS starting from source, 
    193         // then return true, else false
    194         return visited[t] == true;
    195       }
    196     }
    197   }
    198 }

    运行结果如下:

    参考资料

    本篇文章《Ford-Fulkerson 最大流算法》由 Dennis Gao 发表自博客园,未经作者本人同意禁止任何形式的转载,任何自动或人为的爬虫转载行为均为耍流氓。

  • 相关阅读:
    Asp.net MVC 视图引擎集合
    技术债务管理计划
    Android应用程序反编译
    Managed Extensibility Framework(MEF) 2 框架新特性介绍
    企业搜索引擎开发之连接器connector(十四)
    企业搜索引擎开发之连接器connector(十)
    企业搜索引擎开发之连接器connector(十一)
    zookeeper 原理
    企业搜索引擎开发之连接器connector(十二)
    jspf插件框架
  • 原文地址:https://www.cnblogs.com/gaochundong/p/ford_fulkerson_maximum_flow_algorithm.html
Copyright © 2020-2023  润新知