网络流EK算法模板

\(EK\)算法的思想就是每一次找一条增广路进行增广。

注意几个点:

  • 存图时\(head\)数组要设为\(-1\)
  • 存图的代码是这样的:
inline void add(int u, int v, int w)
{
    ver[tot] = v, fro[tot] = u, edge[tot] = w, nxt[tot] = head[u], head[u] = tot++;
    ver[tot] = u, fro[tot] = v, edge[tot] = 0, nxt[tot] = head[v], head[v] = tot++;//注意最后才tot++,且需要建流量为0的反边
}

具体实现参考代码:

#include <bits/stdc++.h>
#define itn int
#define gI gi

using namespace std;

inline int gi()
{
    int f = 1, x = 0; char c = getchar();
    while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
    while (c >= '0' && c <= '9') x = x * 10 + (c ^ 48), c = getchar();
    return f * x;
}

const int maxn = 100003;

int n, m, s, t, tot, fro[maxn * 2], head[maxn], ver[maxn * 2], nxt[maxn * 2], edge[maxn * 2];
int flow[maxn], pre[maxn], pos[maxn], ans;

inline void add(int u, int v, int w)
{
    ver[tot] = v, fro[tot] = u, edge[tot] = w, nxt[tot] = head[u], head[u] = tot++;
    ver[tot] = u, fro[tot] = v, edge[tot] = 0, nxt[tot] = head[v], head[v] = tot++;
}

queue <int> q;

inline int Max_flow(int s, int t)
{
    memset(pos, -1, sizeof(pos));
    memset(pre, -1, sizeof(pre));
    while (!q.empty()) q.pop();
    q.push(s);
    flow[s] = 0x3f3f3f3f;
    //以上为初始化
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        if (u == t) return flow[u];//找到了一条增广路
        for (int i = head[u]; i != -1; i = nxt[i])//遍历出边
        {
            int v = ver[i], w = edge[i];
            if (pre[v] == -1 && w > 0)//下一个点还可以增广
            {
                pre[v] = u;//记录前驱
                pos[v] = i;//记录当前边的编号
                flow[v] = min(flow[u], w);//记录流量
                q.push(v);//放入队列
            }
        }
    }
    return -1;
}

inline void EK(int s, int t)
{
    int ins = 0;
    while ((ins = Max_flow(s, t)) != -1)//当前还存在增广路
    {
        int k = t;//向前推进
        while (k != s)
        {
            edge[pos[k]] -= ins;//边的流量减去当前增广出的最大流量
            edge[pos[k] ^ 1] += ins;//反边则加上最大流量
            k = pre[k];//向前记录
        }
        ans += ins;//增加答案
    }
}

int main()
{
    n = gi(), m = gi(), s = gi(), t = gi();
    memset(head, -1, sizeof(head));//记得初始值设为-1
    for (int i = 1; i <= m; i+=1)
    {
        int u = gi(), v = gi(), w = gi();
        add(u, v, w);//建边
    }
    EK(s, t);//EK算法跑网络流
    printf("%d\n", ans);//输出答案
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/xsl19/p/maxflow-ek.html