【算法模板】Dinic

以下内容摘自OI Wiki
Dinic算法的过程是这样的:每次增广前,我们先用BFS来将图分层。
设源点的层数为0,那么一个点的层数便是它离源点的最近距离。
通过分层,我们可以干两件事情:
如果不存在到汇点的增广路(即汇点的层数不存在),我们即可停止增广。
确保我们找到的增广路是最短的。(原因见下文)

接下来是 DFS 找增广路的过程。
我们每次找增广路的时候,都只找比当前点层数多1的点进行增广(这样就可以确保我们找到的增广路是最短的)。

Dinic 算法有两个优化:
多路增广:每次找到一条增广路的时候,如果残余流量没有用完怎么办呢?我们可以利用残余部分流量,再找出一条增广路。这样就可以在一次DFS中找出多条增广路,大大提高了算法的效率。
当前弧优化:如果一条边已经被增广过,那么它就没有可能被增广第二次。那么,我们下一次进行增广的时候,就可以不必再走那些已经被增广过的边。

容易知道,每次增广后最短路径的长度都会增加,故最多进行n-1次DFS,而每次DFS的时间不超过O(nm),总的时间复杂度一定小于O(n^2m),实际上远小于这个复杂度。

struct Edge {
    int from, to, cap, flow;
};
struct Dinic {
    int s, t;
    bool vis[N];
    int d[N];
    int cur[N];

    vector<Edge> edges;
    vector<int> G[N];
    void AddEdge(int from, int to, int cap) {
        edges.push_back({from, to, cap, 0});
        edges.push_back({to, from, 0, 0); 
        //edges.push_back({to, from, cap, 0}); 如果是无向图.
        G[from].push_back(edges.size() - 2);
        G[to].push_back(edges.size() - 1);
    }

    bool BFS() {
        memset(vis, 0, sizeof(vis));
        queue<int> Q;
        Q.push(s);
        d[s] = 0;
        vis[s] = 1;
        while (!Q.empty()) {
            int u = Q.front(); Q.pop();
            for (int i = 0; i < G[u].size(); i++) {
                Edge& e = edges[G[u][i]];
                int v = e.to;
                if (!vis[v] && e.cap > e.flow) {
                    vis[v] = 1;
                    d[v] = d[u] + 1;
                    Q.push(v);
                }
            }
        }
        return vis[t];
    }

    int DFS(int u, int a) {
        if (u == t || a == 0) return a;
        int flow = 0, f;
        for (int& i = cur[u]; i < G[u].size(); i++) {   //这里取引用,使得u的当前弧被i改变,再次访问到u时,将跳过u已经访问过的支路
            Edge& e = edges[G[u][i]], ee = edges[G[u][i] ^ 1];
            int v = e.to;
            if (d[v] == d[u] + 1 && (f = DFS(v, min(a, e.cap - e.flow))) > 0) {
                e.flow += f;
                ee.flow -= f;
                flow += f;
                a -= f;
                if (a == 0) break;
            }
        }
        return flow;
    }

    int Maxflow(int s, int t) {
        this->s = s; this->t = t;
        int flow = 0;
        while (BFS()) {
            memset(cur, 0, sizeof(cur));
            flow += DFS(s, INF);
        }
        return flow;
    }
};
posted @ 2022-04-09 23:07  _vv123  阅读(55)  评论(0编辑  收藏  举报