求最大流Ford-Fulkerson方法(Edmonds-Karp算法)

基本思路:

算法导论第26章

  1. 使用反平行边来模拟残存网络
  2. 在残存网络中用广搜来寻找增广路径(用pre数组记录前驱结点)。
  3. 如找不到增广路径,已达到最大流,结束
  4. 如找到增广路径,最大流的增值为增广路径上的权值的最小值。
  5. 更新残存网络(从汇点通过前驱数组沿增广路径向前更新)。
  6. 更新最大流。
  7. 转步骤2。

    example:

    如下图找出从节点16的最大流。
    求最大流Ford-Fulkerson方法(Edmonds-Karp算法)_第1张图片

输入:

6 9
1 2 16
2 4 12
4 6 20
5 6 4
3 5 14
1 3 13
3 2 4
4 3 9
5 4 7
1 6

输出:

23

#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
#define MAXN 5000
using namespace std;
int n, S, T;                 //节点数,源点,汇点
vector<vector<int>> capacity;//残存网络的邻接矩阵
queue<int> qu;               //广搜队列
int pre[MAXN], flow[MAXN];   //前驱数组;增广路径中的节点流
int find_augmenting_path(int s, int t) {
    int index;
    size_t i;
    memset(pre, -1, n * sizeof(int));
    while (!qu.empty()) qu.pop();
    flow[s] = INF; //源点的流为INF
    qu.push(s);
    while (!qu.empty()) {
        index = qu.front();
        qu.pop();
        if (index == t)break; //找到了一条增广路径
        for (i = 0; i < n; ++i) 
            if (i != s && capacity[index][i] > 0 && pre[i] == -1) {//每个节点只遍历一次
                pre[i] = index;
                flow[i] = min(capacity[index][i], flow[index]);
                qu.push(i);
            }
    }
    if (pre[t] == -1)return 0;
    return flow[t];

}
int maxflow(int s, int t) {
    int sumflow = 0, increaseflow, v, prenode;
    while (increaseflow = find_augmenting_path(s, t)){
        v = t;
        while (v != s) { //从汇点通过前驱数组向源点更新残存网络
            prenode = pre[v];
            capacity[prenode][v] -= increaseflow;
            capacity[v][prenode] += increaseflow;
            v = prenode;
        }
        sumflow += increaseflow;
    }
    return sumflow;
}
int main() {
    size_t i, m;
    int s, t, c;
    while (cin >> n >> m ) {
        capacity.assign(n, vector<int>(n, 0));
        for (i = 0; i < m; ++i) {
            cin >> s >> t >> c;
            s--, t--;
            capacity[s][t] = c;
        }
        cin >> S >> T;
        cout << maxflow(S - 1, T - 1) << endl;
    }
    return 0;
}

你可能感兴趣的:(算法)