Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Lập Trình

Thuật toán Ford-Fulkerson

Thuật toán Ford-Fulkerson được dùng để phát hiện luồng cực đại từ đỉnh nguồn đến đỉnh hố (sink) trong một đồ thị cho trước. Trong đồ thị này, mỗi cạnh có dung lượng. Hai đỉnh được cung cấp tên là Source (nguồn) và Sink (hố). Đỉnh nguồn có tất cả cạnh ra, không có cạnh vào, và đỉnh hố sẽ có tất cả cạnh vào, không có cạnh ra.

Thuật toán Ford-Fulkerson

Có một số ràng buộc:

  • Luồng trên một cạnh không vượt quá dung lượng cho trước của cạnh đó.
  • Luồng vào và luồng ra cũng sẽ bằng nhau cho mọi cạnh, trừ đỉnh nguồn và đỉnh hố.

Đầu vào và Đầu ra

Đầu vào: Ma trận kề:
0 10 0 10 0 0
0 0 4 2 8 0
0 0 0 0 0 10
0 0 0 0 9 0
0 0 6 0 0 10
0 0 0 0 0 0
Đầu ra: Luồng cực đại là: 19

Thuật toán

bfs(vert, start, sink)

Đầu vào: Danh sách đỉnh, nút bắt đầu, và nút hố.

Đầu ra: True khi nút hố được thăm.

Bắt đầu
  ban đầu đánh dấu tất cả nút là chưa thăm
  trạng thái của start là đã thăm
  tiền nhiệm của nút bắt đầu là ∅
  chèn start vào hàng đợi qu
  trong khi qu không rỗng, thực hiện
    xóa phần tử từ hàng đợi gán vào đỉnh u
    với mọi đỉnh i trong đồ thị dư, thực hiện
      nếu u và i kết nối, và i chưa thăm, thì
        thêm đỉnh i vào hàng đợi
        tiền nhiệm của i là u
        đánh dấu i là đã thăm
      kết thúc
    kết thúc
  kết thúc
  trả về true nếu trạng thái của đỉnh hố là đã thăm
Kết thúc

fordFulkerson(vert, source, sink)

Đầu vào: Danh sách đỉnh, đỉnh nguồn, và đỉnh hố.

Đầu ra: Luồng cực đại từ nguồn đến hố.

Bắt đầu
  tạo đồ thị dư và sao chép đồ thị cho trước vào nó
  trong khi bfs(vert, source, sink) là true, thực hiện
    pathFlow := ∞
    v := đỉnh hố
    trong khi v ≠ đỉnh bắt đầu, thực hiện
      u := tiền nhiệm của v
      pathFlow := minimum của pathFlow và residualGraph[u, v]
      v := tiền nhiệm của v
    kết thúc
    v := đỉnh hố
    trong khi v ≠ đỉnh bắt đầu, thực hiện
      u := tiền nhiệm của v
      residualGraph[u,v] := residualGraph[u,v] - pathFlow
      residualGraph[v,u] := residualGraph[v,u] - pathFlow
      v := tiền nhiệm của v
    kết thúc
    maxFlow := maxFlow + pathFlow
  kết thúc
  trả về maxFlow
Kết thúc

Ví dụ (C++)

#include <iostream>
#include <queue>
#define NODE 6
using namespace std;

typedef struct node {
  int val;
  int state; // trạng thái
  int pred;  // tiền nhiệm
} node;

int minimum(int a, int b) {
  return (a < b) ? a : b;
}

int resGraph[NODE][NODE];

/* int graph[NODE][NODE] = {
  {0, 16, 13, 0, 0, 0},
  {0, 0, 10, 12, 0, 0},
  {0, 4, 0, 0, 14, 0},
  {0, 0, 9, 0, 0, 20},
  {0, 0, 0, 7, 0, 4},
  {0, 0, 0, 0, 0, 0}
}; */

int graph[NODE][NODE] = {
  {0, 10, 0, 10, 0, 0},
  {0, 0, 4, 2, 8, 0},
  {0, 0, 0, 0, 0, 10},
  {0, 0, 0, 0, 9, 0},
  {0, 0, 6, 0, 0, 10},
  {0, 0, 0, 0, 0, 0}
};

int bfs(node *vert, node start, node sink) {
  node u;
  int i, j;
  queue<node> que;
  
  for(i = 0; i < NODE; i++) {
    vert[i].state = 0; // chưa thăm
  }
  vert[start.val].state = 1; // đã thăm
  vert[start.val].pred = -1; // không có nút cha
  que.push(start); // chèn nút bắt đầu
  
  while(!que.empty()) {
    u = que.front();
    que.pop();
    for(i = 0; i < NODE; i++) {
      if(resGraph[u.val][i] > 0 && vert[i].state == 0) {
        que.push(vert[i]);
        vert[i].pred = u.val;
        vert[i].state = 1;
      }
    }
  }
  return (vert[sink.val].state == 1);
}

int fordFulkerson(node *vert, node source, node sink) {
  int maxFlow = 0;
  int u, v;
  
  for(int i = 0; i < NODE; i++) {
    for(int j = 0; j < NODE; j++) {
      resGraph[i][j] = graph[i][j]; // ban đầu đồ thị dư là đồ thị chính
    }
  }
  
  while(bfs(vert, source, sink)) {
    // tìm đường tăng luồng dùng BFS
    int pathFlow = 999; // như vô cực
    for(v = sink.val; v != source.val; v = vert[v].pred) {
      u = vert[v].pred;
      pathFlow = minimum(pathFlow, resGraph[u][v]);
    }
    
    for(v = sink.val; v != source.val; v = vert[v].pred) {
      u = vert[v].pred;
      resGraph[u][v] -= pathFlow; // cập nhật dung lượng dư của cạnh
      resGraph[v][u] += pathFlow; // cập nhật dung lượng dư của cạnh ngược
    }
    
    maxFlow += pathFlow;
  }
  return maxFlow; // luồng cực đại tổng thể
}

int main() {
  node vertices[NODE];
  node source, sink;
  for(int i = 0; i < NODE; i++) {
    vertices[i].val = i;
  }
  source.val = 0;
  sink.val = 5;
  int maxFlow = fordFulkerson(vertices, source, sink);
  cout << "Maximum flow is: " << maxFlow << endl;
}

Đầu ra

Maximum flow is: 19