HDU 1532 Drainage Ditches【最大流 | Edmonds-Karp模板】

题目链接

题目描述:

最大流Edmonds-Karp算法模板题。


最大流

最大流问题是基于有向图的,就是求两点 (分别称为源点、汇点) 间的最大流量,图中任何点都可以作为它们的中转。在求最大流时需要满足以下 3 个性质:

  1. 流量守恒。从源点 s 流出的流量和到达汇点 t 的流量相等;其他所有中转点,流入和流出相等。
  2. 反对称性。设从 u u u v v v 的流量是 f ( u , v ) f(u,v) f(u,v) v v v u u u 流量是 f ( v , u ) f(v,u) f(v,u),那么 f ( u , v ) = − f ( v , u ) f(u,v)=-f(v,u) f(u,v)=f(v,u)
  3. 容量限制。每个边的实际流量不大于最大容量。

Ford-Fulkerson方法

Edmonds-Karp算法是Ford-Fulkerson方法的一种实现。所谓Ford-Fulkerson方法,是一种非常容易理解的算法思想:

  1. 在初始的时候,所有边上的为 0。
  2. 找到一条从 s 到 t 的路径,按 3 个性质得到这条路径上的最大值,更新每个边的“残留容量”(后面会介绍,不是单纯的减)。残留容量在后序步骤中继续使用。
  3. 重复步骤 2,直到找不到路径。

Ford-Fulkerson方法基本上就是上述的思路,它有 3 个思想:

  1. 残留网路:迭代后残留容量所产生的图,每次新的迭代在上一次的残留网络上进行。上面讲的每条边残留容量指的是每当一条边使用了 c c c 流量后,在这条边上补充反向路径,其值就是 c c c,这样形成的新的网络就是残留网络。残留网络可以这样理解:残留网络给了一些路径“反悔”的机会,关于反向边的进一步理解,可以参考这篇文章最大流反向边
  2. 增广路:在残留网络上找到一条从 s 到 t 的路径。
  3. 割:Ford-Fulkerson方法的正确性是最大流最小割定理的推论:一个流是最大流,当且仅当它的残留网路不包含增广路径时。

Edmonds-Karp算法

如果用 BFS 来计算增广路径,就是 Edmonds-Karp算法。
复杂度:经过 O ( V E ) O(VE) O(VE) 次 BFS 迭代,所有增广路被找到;一次 BFS 的时间是 O ( E ) O(E) O(E),所以总的时间复杂度是 O ( V E 2 ) O(VE^2) O(VE2)
由于Edmonds-Karp算法的复杂度较高,只能用于小图,所以用邻接矩阵存图就行了。
Edmonds-Karp算法代码实现较少,用起来比较方便。


AC Codes:

#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
//#include <unordered_set>
//#include <unordered_map>
#include <deque>
#include <list>
#include <iomanip>
#include <algorithm>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
//#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
//cout << fixed << setprecision(2);
//cout << setw(2);
const int N = 2e2 + 6, M = 1e9 + 7, INF = 0x3f3f3f3f;

int n, m;
int g[N][N], pre[N], flow[N], d[N];

int Edmonds_Karp(int s, int t) {
    int max_flow = 0;
    while (1) {
        memset(pre, -1, sizeof pre);
        memset(d, 0x3f, sizeof d);
        memset(flow, 0, sizeof flow);
        flow[s] = INF, d[s] = 0;
        queue<int> Q;
        Q.push(s);
        while (!Q.empty()) {
            int u = Q.front();
            Q.pop();
            if (u == t) break;
            for (int v = 1; v <= n; v++) {
                if (v != s && g[u][v] > 0 && d[v] == INF) {
                    pre[v] = u, d[v] = d[u] + 1, flow[v] = min(flow[u], g[u][v]);
                    Q.push(v);
                }
            }
        }
        if (d[t] == INF) break;
        max_flow += flow[t];
        int cur = t;
        while (cur != s) {
            int fa = pre[cur];
            g[fa][cur] -= flow[t], g[cur][fa] += flow[t];
            cur = fa;
        }
    }
    return max_flow;
}

int main() {
    //freopen("/Users/xumingfei/Desktop/ACM/test.txt", "r", stdin);
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    while (cin >> m >> n) {
        memset(g, 0, sizeof g);
        int x, y, z;
        for (int i = 0; i < m; i++) {
            cin >> x >> y >> z;
            g[x][y] += z; 
        }
        cout << Edmonds_Karp(1, n) << '\n';
    }
    return 0;
}
©️2020 CSDN 皮肤主题: 1024 设计师:上身试试 返回首页