原文: https://www.programiz.com/dsa/ford-fulkerson-algorithm

在本教程中,您将学习什么是 Ford-Fulkerson 算法。 此外,您还将找到在 C,C++ ,Java 和 Python 中找到流网络中最大流的工作示例。

Ford-Fulkerson 算法是一种贪婪方法,用于计算网络或图形中的最大可能流量。

术语网络流用于描述具有源(S)和宿(T)的顶点和边的网络。 除了ST之外,每个顶点都可以通过它接收和发送相同数量的东西。 S只能发送,T只能接收东西。

我们可以使用不同容量的管网内部的液体流动来可视化对算法的理解。 每个管道在特定情况下都可以传输一定容量的液体。 对于此算法,我们将查找使用网络在实例处可以从源流向水槽的液体量。

Ford-Fulkerson 算法 - 图1

图的网络流


使用的术语

增广路径

它是流网络中可用的路径。

剩余图

它表示具有其他可能流量的网络流。

剩余容量

从最大容量中减去流量后的边容量。


Ford-Fulkerson 算法如何工作?

该算法如下:

  1. 将所有边中的流初始化为 0。
  2. 当源和接收器之间存在增加路径时,将此路径添加到流中。
  3. 更新剩余图。

如果需要,我们还可以考虑反向路径,因为如果不考虑反向路径,则可能永远找不到最大流量。

通过以下示例可以理解上述概念。


Ford-Fulkerson 的例子

开始时所有边的流为 0。

Ford-Fulkerson 算法 - 图2

图的网络流示例

  1. 选择从ST的任意路径。在此步骤中,我们选择了路径S-A-B-T
    Ford-Fulkerson 算法 - 图3
    找到路径
    三个边之间的最小容量为 2(B-T)。 基于此,为每个路径更新流量/容量。
    Ford-Fulkerson 算法 - 图4
    更新容量

  2. 选择其他路径S-D-C-T。 这些边之间的最小容量为 3(S-D)。
    Ford-Fulkerson 算法 - 图5
    查找下一个路径
    根据此更新容量。
    Ford-Fulkerson 算法 - 图6
    更新容量

  3. 现在,让我们考虑反向路径B-D。 选择路径S-A-B-D-C-T。 边之间的最小剩余容量为 1(D-C)。
    Ford-Fulkerson 算法 - 图7
    查找下一个路径
    正在更新容量。
    Ford-Fulkerson 算法 - 图8
    更新容量
    分别考虑正向和反向路径的容量。

  4. 将所有流量相加,2 + 3 + 1 = 6,这是网络流上的最大可能流量。

请注意,如果任何边的容量已满,则无法使用该路径。


Python,Java 和 C/C++ 示例

  1. # Ford-Fulkerson algorith in Python
  2. from collections import defaultdict
  3. class Graph:
  4. def __init__(self, graph):
  5. self.graph = graph
  6. self. ROW = len(graph)
  7. # Using BFS as a searching algorithm
  8. def searching_algo_BFS(self, s, t, parent):
  9. visited = [False] * (self.ROW)
  10. queue = []
  11. queue.append(s)
  12. visited[s] = True
  13. while queue:
  14. u = queue.pop(0)
  15. for ind, val in enumerate(self.graph[u]):
  16. if visited[ind] == False and val > 0:
  17. queue.append(ind)
  18. visited[ind] = True
  19. parent[ind] = u
  20. return True if visited[t] else False
  21. # Applying fordfulkerson algorithm
  22. def ford_fulkerson(self, source, sink):
  23. parent = [-1] * (self.ROW)
  24. max_flow = 0
  25. while self.searching_algo_BFS(source, sink, parent):
  26. path_flow = float("Inf")
  27. s = sink
  28. while(s != source):
  29. path_flow = min(path_flow, self.graph[parent[s]][s])
  30. s = parent[s]
  31. # Adding the path flows
  32. max_flow += path_flow
  33. # Updating the residual values of edges
  34. v = sink
  35. while(v != source):
  36. u = parent[v]
  37. self.graph[u][v] -= path_flow
  38. self.graph[v][u] += path_flow
  39. v = parent[v]
  40. return max_flow
  41. graph = [[0, 8, 0, 0, 3, 0],
  42. [0, 0, 9, 0, 0, 0],
  43. [0, 0, 0, 0, 7, 2],
  44. [0, 0, 0, 0, 0, 5],
  45. [0, 0, 7, 4, 0, 0],
  46. [0, 0, 0, 0, 0, 0]]
  47. g = Graph(graph)
  48. source = 0
  49. sink = 5
  50. print("Max Flow: %d " % g.ford_fulkerson(source, sink))
  1. // Ford-Fulkerson algorith in Java
  2. import java.util.LinkedList;
  3. class FordFulkerson {
  4. static final int V = 6;
  5. // Using BFS as a searching algorithm
  6. boolean bfs(int Graph[][], int s, int t, int p[]) {
  7. boolean visited[] = new boolean[V];
  8. for (int i = 0; i < V; ++i)
  9. visited[i] = false;
  10. LinkedList<Integer> queue = new LinkedList<Integer>();
  11. queue.add(s);
  12. visited[s] = true;
  13. p[s] = -1;
  14. while (queue.size() != 0) {
  15. int u = queue.poll();
  16. for (int v = 0; v < V; v++) {
  17. if (visited[v] == false && Graph[u][v] > 0) {
  18. queue.add(v);
  19. p[v] = u;
  20. visited[v] = true;
  21. }
  22. }
  23. }
  24. return (visited[t] == true);
  25. }
  26. // Applying fordfulkerson algorithm
  27. int fordFulkerson(int graph[][], int s, int t) {
  28. int u, v;
  29. int Graph[][] = new int[V][V];
  30. for (u = 0; u < V; u++)
  31. for (v = 0; v < V; v++)
  32. Graph[u][v] = graph[u][v];
  33. int p[] = new int[V];
  34. int max_flow = 0;
  35. # Updating the residual calues of edges
  36. while (bfs(Graph, s, t, p)) {
  37. int path_flow = Integer.MAX_VALUE;
  38. for (v = t; v != s; v = p[v]) {
  39. u = p[v];
  40. path_flow = Math.min(path_flow, Graph[u][v]);
  41. }
  42. for (v = t; v != s; v = p[v]) {
  43. u = p[v];
  44. Graph[u][v] -= path_flow;
  45. Graph[v][u] += path_flow;
  46. }
  47. // Adding the path flows
  48. max_flow += path_flow;
  49. }
  50. return max_flow;
  51. }
  52. public static void main(String[] args) throws java.lang.Exception {
  53. int graph[][] = new int[][] { { 0, 8, 0, 0, 3, 0 }, { 0, 0, 9, 0, 0, 0 }, { 0, 0, 0, 0, 7, 2 },
  54. { 0, 0, 0, 0, 0, 5 }, { 0, 0, 7, 4, 0, 0 }, { 0, 0, 0, 0, 0, 0 } };
  55. FordFulkerson m = new FordFulkerson();
  56. System.out.println("Max Flow: " + m.fordFulkerson(graph, 0, 5));
  57. }
  58. }
  1. / Ford - Fulkerson algorith in C
  2. #include <stdio.h>
  3. #define A 0
  4. #define B 1
  5. #define C 2
  6. #define MAX_NODES 1000
  7. #define O 1000000000
  8. int n;
  9. int e;
  10. int capacity[MAX_NODES][MAX_NODES];
  11. int flow[MAX_NODES][MAX_NODES];
  12. int color[MAX_NODES];
  13. int pred[MAX_NODES];
  14. int min(int x, int y) {
  15. return x < y ? x : y;
  16. }
  17. int head, tail;
  18. int q[MAX_NODES + 2];
  19. void enqueue(int x) {
  20. q[tail] = x;
  21. tail++;
  22. color[x] = B;
  23. }
  24. int dequeue() {
  25. int x = q[head];
  26. head++;
  27. color[x] = C;
  28. return x;
  29. }
  30. // Using BFS as a searching algorithm
  31. int bfs(int start, int target) {
  32. int u, v;
  33. for (u = 0; u < n; u++) {
  34. color[u] = A;
  35. }
  36. head = tail = 0;
  37. enqueue(start);
  38. pred[start] = -1;
  39. while (head != tail) {
  40. u = dequeue();
  41. for (v = 0; v < n; v++) {
  42. if (color[v] == A && capacity[u][v] - flow[u][v] > 0) {
  43. enqueue(v);
  44. pred[v] = u;
  45. }
  46. }
  47. }
  48. return color[target] == C;
  49. }
  50. // Applying fordfulkerson algorithm
  51. int fordFulkerson(int source, int sink) {
  52. int i, j, u;
  53. int max_flow = 0;
  54. for (i = 0; i < n; i++) {
  55. for (j = 0; j < n; j++) {
  56. flow[i][j] = 0;
  57. }
  58. }
  59. // Updating the residual values of edges
  60. while (bfs(source, sink)) {
  61. int increment = O;
  62. for (u = n - 1; pred[u] >= 0; u = pred[u]) {
  63. increment = min(increment, capacity[pred[u]][u] - flow[pred[u]][u]);
  64. }
  65. for (u = n - 1; pred[u] >= 0; u = pred[u]) {
  66. flow[pred[u]][u] += increment;
  67. flow[u][pred[u]] -= increment;
  68. }
  69. // Adding the path flows
  70. max_flow += increment;
  71. }
  72. return max_flow;
  73. }
  74. int main() {
  75. for (int i = 0; i < n; i++) {
  76. for (int j = 0; j < n; j++) {
  77. capacity[i][j] = 0;
  78. }
  79. }
  80. n = 6;
  81. e = 7;
  82. capacity[0][1] = 8;
  83. capacity[0][4] = 3;
  84. capacity[1][2] = 9;
  85. capacity[2][4] = 7;
  86. capacity[2][5] = 2;
  87. capacity[3][5] = 5;
  88. capacity[4][2] = 7;
  89. capacity[4][3] = 4;
  90. int s = 0, t = 5;
  91. printf("Max Flow: %d\n", fordFulkerson(s, t));
  92. }
// Ford-Fulkerson algorith in C++

#include <limits.h>
#include <string.h>

#include <iostream>
#include <queue>
using namespace std;

#define V 6

// Using BFS as a searching algorithm
bool bfs(int rGraph[V][V], int s, int t, int parent[]) {
  bool visited[V];
  memset(visited, 0, sizeof(visited));

  queue<int> q;
  q.push(s);
  visited[s] = true;
  parent[s] = -1;

  while (!q.empty()) {
    int u = q.front();
    q.pop();

    for (int v = 0; v < V; v++) {
      if (visited[v] == false && rGraph[u][v] > 0) {
        q.push(v);
        parent[v] = u;
        visited[v] = true;
      }
    }
  }

  return (visited[t] == true);
}

// Applying fordfulkerson algorithm
int fordFulkerson(int graph[V][V], int s, int t) {
  int u, v;

  int rGraph[V][V];
  for (u = 0; u < V; u++)
    for (v = 0; v < V; v++)
      rGraph[u][v] = graph[u][v];

  int parent[V];
  int max_flow = 0;

  // Updating the residual values of edges
  while (bfs(rGraph, s, t, parent)) {
    int path_flow = INT_MAX;
    for (v = t; v != s; v = parent[v]) {
      u = parent[v];
      path_flow = min(path_flow, rGraph[u][v]);
    }

    for (v = t; v != s; v = parent[v]) {
      u = parent[v];
      rGraph[u][v] -= path_flow;
      rGraph[v][u] += path_flow;
    }

    // Adding the path flows
    max_flow += path_flow;
  }

  return max_flow;
}

int main() {
  int graph[V][V] = {{0, 8, 0, 0, 3, 0},
             {0, 0, 9, 0, 0, 0},
             {0, 0, 0, 0, 7, 2},
             {0, 0, 0, 0, 0, 5},
             {0, 0, 7, 4, 0, 0},
             {0, 0, 0, 0, 0, 0}};

  cout << "Max Flow: " << fordFulkerson(graph, 0, 5) << endl;
}

Ford-Fulkerson 应用

  • 输水管道
  • 二分匹配问题
  • 按需流动