流网络(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。
流网络(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∈V
f(u, v) = 0。
f(u, v) 称为从顶点 u 到顶点 v 的流,流的值定义为:|f| =Σ
v∈V
f(s, v),即从源点 s 出发的总流。
最大流问题(Maximum-flow problem)中,给出源点 s 和汇点 t 的流网络 G,希望找出从 s 到 t 的最大值流。
满足流网络的性质的实际上定义了问题的限制:
经过边的流不能超过边的容量;
除了源点 s 和汇点 t,对于其它所有顶点,流入量与流出量要相等;
上面的图中描述的流网络可简化为下图,其中源点 s = 0,汇点 t = 5。
上图的最大流为 23,流向如下图所示。
Ford-Fulkerson 算法是一种解决最大流的方法,其依赖于三种重要思想:
残留网络(Residual networks)
增广路径(Augmenting paths)
割(Cut)
这些思想是最大流最小割定理的精髓,该定理用流网络的割来描述最大流的值。
最大流最小割定理
如果 f 是具有源点 s 和汇点 t 的流网络 G = (V, E) 中的一个流,则下列条件是等价的:
f 是 G 的一个最大流。
残留网络 G
f
不包含增广路径。
对 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;
5 namespace GraphAlgorithmTesting
7 class Program
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);
23 Console.WriteLine();
24 Console.WriteLine("Graph Vertex Count : {0}", g.VertexCount);
25 Console.WriteLine("Graph Edge Count : {0}", g.EdgeCount);
26 Console.WriteLine();
28 int maxFlow = g.FordFulkerson(0, 5);
29 Console.WriteLine("The Max Flow is : {0}", maxFlow);
31 Console.ReadKey();
32 }
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 }
43 public int Begin { get; private set; }
44 public int End { get; private set; }
45 public int Weight { get; private set; }
47 public override string ToString()
48 {
49 return string.Format(
50 "Begin[{0}], End[{1}], Weight[{2}]",
51 Begin, End, Weight);
52 }
53 }
55 class Graph
56 {
57 private Dictionary<int, List<Edge>> _adjacentEdges
58 = new Dictionary<int, List<Edge>>();
60 public Graph(int vertexCount)
61 {
62 this.VertexCount = vertexCount;
63 }
65 public int VertexCount { get; private set; }
67 public IEnumerable<int> Vertices
68 {
69 get
70 {
71 return _adjacentEdges.Keys;
72 }
73 }
75 public IEnumerable<Edge> Edges
76 {
77 get
78 {
79 return _adjacentEdges.Values.SelectMany(e => e);
80 }
81 }
83 public int EdgeCount
84 {
85 get
86 {
87 return this.Edges.Count();
88 }
89 }
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 }
99 _adjacentEdges[begin].Add(new Edge(begin, end, weight));
100 }
102 public int FordFulkerson(int s, int t)
103 {
104 int u, v;
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];
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 }
122 // This array is filled by BFS and to store path
123 int[] parent = new int[VertexCount];
125 // There is no flow initially
126 int maxFlow = 0;
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 }
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 }
151 // Add path flow to overall flow
152 maxFlow += pathFlow;
153 }
155 // Return the overall flow
156 return maxFlow;
157 }
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 }
169 Queue<int> q = new Queue<int>();
171 visited[s] = true;
172 q.Enqueue(s);
173 parent[s] = -1;
175 // standard BFS loop
176 while (q.Count > 0)
177 {
178 int u = q.Dequeue();
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 }
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 }
运行结果如下:
广度优先搜索
深度优先搜索
Breadth First Traversal for a Graph
Depth First Traversal for a Graph
Dijkstra 单源最短路径算法
Bellman-Ford 单源最短路径算法
Bellman–Ford algorithm
Introduction To Algorithm
Floyd-Warshall's algorithm
Bellman-Ford algorithm for single-source shortest paths
Dynamic Programming | Set 23 (Bellman–Ford Algorithm)
Dynamic Programming | Set 16 (Floyd Warshall Algorithm)
Johnson’s algorithm for All-pairs shortest paths
Floyd-Warshall's algorithm
最短路径算法--Dijkstra算法,Bellmanford算法,Floyd算法,Johnson算法
QuickGraph, Graph Data Structures And Algorithms for .NET
CHAPTER 26: ALL-PAIRS SHORTEST PATHS
本篇文章《
Ford-Fulkerson 最大流算法
》由
Dennis Gao
发表自
博客园
,未经作者本人同意禁止任何形式的转载,任何自动或人为的爬虫转载行为均为耍流氓。