Template -「网络流 & 二分图」

EK.

很少用到,知道思想即可。

懒得写封装的屑。

queue<int> q;
int Cap[MAXN][MAXN], Flow[MAXN][MAXN], Aug[MAXN], fa[MAXN], n;
void Add_Cap(int u, int v, int C) { Cap[u][v] += C; }

int bfs(int s, int t) {
    for(int i = 1; i <= n; i++) {
        Aug[i] = 0;
        fa[i] = 0;
    }
    while(!q.empty())
        q.pop();
    Aug[s] = INF;
    q.push(s);
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        for(int v = 1; v <= n; v++)
            if(Cap[u][v] - Flow[u][v] > 0 && !Aug[v]) {
                Aug[v] = Min(Aug[u], Cap[u][v] - Flow[u][v]);
                fa[v] = u;
                if(v == t)
                    return Aug[v];
                q.push(v);
            }
    }
    return 0;
}

int EK(int s, int t) {
    int Delta = bfs(s, t), res = 0, u;
    while(Delta) {
        res += Delta;
        for(int v = t; v != s; v = u) {
            u = fa[v];
            Flow[u][v] += Delta;
            Flow[v][u] -= Delta;
        }
        Delta = bfs(s, t);
    }
    return res;
}

Dinic.

时间复杂度玄学的常用最大流板子。

struct Maximum_Flow {
    #define Type int
    struct Edge  {
        int v, Nxt;
        Edge () {}
        Edge (int V, int N) {
            v = V, Nxt = N;
        }
    } e[Maxm << 1];
    int n, Cnt, s, t;
    Type Cap[Maxm << 1], Flow[Maxm << 1];
    int Lab[Maxn], Cur[Maxn], Head[Maxn], Col[Maxn];
    queue <int> q;

    void Init (int N, int S, int T) {
        for (int i = 0; i <= Cnt; i++)
            Flow[i] = 0, Cap[i] = 0;
        n = N, Cnt = 0, s = S, t = T;
        for (int i = 1; i <= n; i++)
            Head[i] = -1, Col[i] = 0;
    }

    void Add_Edge (int u, int v, Type w) {
        Cap[Cnt] += w;
        e[Cnt] = Edge (v, Head[u]), Head[u] = Cnt++;
        e[Cnt] = Edge (u, Head[v]), Head[v] = Cnt++;
    }

    bool Lab_Vertex () {
        for (int i = 1; i <= n; i++)
            Lab[i] = 0;
        Lab[t] = 1;
        while (!q.empty ())
            q.pop ();
        q.push (t);
        while (!q.empty ()) {
            int v = q.front (); q.pop ();
            for (int i = Head[v], u; ~i; i = e[i].Nxt) {
                u = e[i].v;
                if (!Lab[u] && Cap[i ^ 1] - Flow[i ^ 1]) {
                    Lab[u] = Lab[v] + 1, q.push (u);
                    if (u == s)
                        return Lab[s];
                }
            }
        }
        return Lab[s];
    }

    Type Widen (int u, Type Limit) {
        if (u == t)
            return Limit;
        Type Used = 0, Delta;
        for (int i = Cur[u], v; ~i; i = e[i].Nxt) {
            v = e[i].v, Cur[u] = i;
            if (Lab[v] + 1 != Lab[u] || Cap[i] - Flow[i] <= 0)
                continue;
            Delta = Widen (v, Min (Limit - Used, Cap[i] - Flow[i]));
            Used += Delta, Flow[i] += Delta, Flow[i ^ 1] -= Delta;
            if (Used == Limit)
                return Used;
        }
        return Used;
    }

    Type Dinic () {
        Type Res = 0;
        while (Lab_Vertex ()) {
            for (int i = 1; i <= n; i++)
                Cur[i] = Head[i];
            Res += Widen (s, Inf);
            if (Res < 0)
                return Inf;
        }
        return Res;
    }

    void Color (int u) {
        Col[u] = 1;
        for (int i = Head[u]; ~i; i = e[i].Nxt) 
            if (Cap[i] - Flow[i] > 0 && !Col[e[i].v])
                Color (e[i].v);
    }

    #undef Type
} Flow_Graph;

spfa + Dinic.

普通最小费用最大流。(小心被卡?

struct Minimum_Cost_Maximum_Flow {
    #define Type int
    struct edge {
        int v, nxt;
        Type Wei, Cap, Flow;
        edge() {}
        edge(int V, int Nxt, Type C, Type W, Type F) {
            v = V, nxt = Nxt, Cap = C, Wei = W, Flow = F;
        }
    } e[MAXM << 1];
    int head[MAXM << 1], cnt = 0;
    void Add_Edge(int u, int v, Type c, Type w) {
        e[cnt] = edge(v, head[u], c, w, 0);
        head[u] = cnt++;
        e[cnt] = edge(u, head[v], 0, -w, 0);
        head[v] = cnt++;
    }

    int Cur[MAXN], n, s, t;
    bool vis[MAXN], Flag[MAXN];
    Type Dist[MAXN], Aug[MAXN], Flow, Cost; 

    void init(int N, int S, int T) {
        n = N, s = S, t = T, cnt = 0;
        for(int i = 1; i <= n; i++)
            head[i] = -1;
    }

    bool spfa() {
        for(int i = 1; i <= n; i++) 
            Dist[i] = INF, vis[i] = false, Aug[i] = INF;
        Dist[s] = 0, vis[s] = true, Aug[s] = INF;
        queue<int> q;
        q.push(s);
        while(!q.empty()) {
            int u = q.front(); q.pop();
            vis[u] = false;
            for(int i = head[u], v; ~i; i = e[i].nxt) {
                v = e[i].v;
                if(e[i].Cap - e[i].Flow > 0 && Dist[v] > Dist[u] + e[i].Wei) {
                    Dist[v] = Dist[u] + e[i].Wei;
                    Aug[v] = Min(Aug[u], e[i].Cap - e[i].Flow);
                    if(!vis[v])
                        vis[v] = true, q.push(v);
                }
            }
        }
        return Dist[t] != INF;
    }

    Type Widen(int u, Type Limit) {
        if(u == t)
            return Limit;
        Flag[u] = true;
        Type Used = 0, Delta;
        for(int i = Cur[u], v; ~i; i = e[i].nxt) {
            v = e[i].v;
            if(Flag[v] || Dist[u] + e[i].Wei != Dist[v] || e[i].Cap - e[i].Flow <= 0)
                continue;
            Cur[u] = i;
            Delta = Widen(v, Min(Limit - Used, e[i].Cap - e[i].Flow));
            Used += Delta, e[i].Flow += Delta, e[i ^ 1].Flow -= Delta;
            if(Used == Limit)
                break;
        }
        Flag[u] = false;
        return Used;
    }

    void Dinic() {
        Flow = 0, Cost = 0;
        Type Delta;
        while(spfa()) {
            for(int i = 1; i <= n; i++)
                Cur[i] = head[i];
            Delta = Widen(s, INF);
            Flow += Delta, Cost += Delta * Dist[t];
        }
    }

    #undef Type
} Flow_Graph;

spfa + Dijkstra + EK.

时间复杂度稳定,不会被卡。呃不会被卡吧。

struct Minimum_Cost_Maximum_Flow {
    #define Type int
    struct edge {
        int v, nxt;
        Type Wei, Cap, Flow;
        edge() {}
        edge(int V, int Nxt, Type C, Type W, Type F) {
            v = V, nxt = Nxt, Cap = C, Wei = W, Flow = F;
        }
    } e[MAXM << 1];
    int head[MAXM << 1], cnt = 0;
    void Add_Edge(int u, int v, Type c, Type w) {
        e[cnt] = edge(v, head[u], c, w, 0);
        head[u] = cnt++;
        e[cnt] = edge(u, head[v], 0, -w, 0);
        head[v] = cnt++;
    }

    struct node {
        int x;
        Type dis;
        node() {}
        node(int X, Type Dis) {
            x = X, dis = Dis;
        }
        friend bool operator < (node One, node TheOther) {
            return One.dis > TheOther.dis;
        }
    };

    struct Back {
        int Pre, id;
        Back() {}
        Back(int P, int Id) {
            Pre = P, id = Id;
        }
    } Last[MAXN];

    int Cur[MAXN], n, s, t;
    bool vis[MAXN], Flag[MAXN];
    Type Dist[MAXN], Aug[MAXN], h[MAXN], Flow, Cost;

    void init(int N, int S, int T) {
        n = N, s = S, t = T, cnt = 0;
        for(int i = 1; i <= n; i++)
            head[i] = -1;
    }

    void spfa(int s, int t) {
        for(int i = 1; i <= n; i++)
            h[i] = INF, vis[i] = false;
        h[s] = 0, vis[s] = true;
        queue<int> q;
        q.push(s);
        while(!q.empty()) {
            int u = q.front(); q.pop();
            vis[u] = false;
            for(int i = head[u], v; ~i; i = e[i].nxt) {
                v = e[i].v;
                if(e[i].Cap - e[i].Flow > 0 && h[v] > h[u] + e[i].Wei) {
                    h[v] = h[u] + e[i].Wei;
                    if(!vis[v])
                        vis[v] = true, q.push(v);
                }
            }
        }
    }

    bool Dijkstra(int s, int t) {
        for(int i = 1; i <= n; i++)
            Dist[i] = INF, Last[i] = Back(-1, -1), vis[i] = false, Aug[i] = INF;
        priority_queue<node> q;
        Dist[s] = 0;
        q.push(node(s, Dist[s]));
        while(!q.empty()) {
            int u = q.top().x; q.pop();
            if(vis[u])
                continue;
            vis[u] = true;
            for(int i = head[u], v; ~i; i = e[i].nxt) {
                v = e[i].v;
                if(e[i].Cap - e[i].Flow > 0 && Dist[v] > Dist[u] + e[i].Wei + h[u] - h[v]) {
                    Last[v] = Back(u, i);
                    Dist[v] = Dist[u] + e[i].Wei + h[u] - h[v];
                    Aug[v] = Min(Aug[u], e[i].Cap - e[i].Flow);
                    q.push(node(v, Dist[v]));
                }
            }
        }
        return Dist[t] != INF;
    }

    void EK() {
        Flow = 0, Cost = 0;
        spfa(s, t);
        while(Dijkstra(s, t)) {
            Flow += Aug[t];
            Cost += Aug[t] * (Dist[t] + h[t]);
            int pos = t;
            while(pos != s) {
                e[Last[pos].id].Flow += Aug[t];
                e[Last[pos].id ^ 1].Flow -= Aug[t];
                pos = Last[pos].Pre;
            }
            for(int i = 1; i <= n; i++)
                h[i] += Dist[i];
        }
    }

    #undef Type
} Flow_Graph;

Kuhn-Munkres.

最大匹配板子。当然你也可以直接 Dinic。

struct Bipartite_Graph {
    struct edge {
        int v, nxt;
        edge() {}
        edge(int V, int Nxt) {
            v = V, nxt = Nxt;
        }
    } e[MAXM << 1];
    int head[MAXN], n, m, cnt;
    void Add_Edge(int u, int v) { 
        e[cnt] = edge(v, head[u]);
        head[u] = cnt++;
    }
    int Mat[MAXN][2], Tim[MAXN], tot;

    void init(int N, int M) {
        n = N, m = M;
        for(int i = 1; i <= n; i++) 
            head[i] = -1, Tim[i] = 0, Mat[i][0] = 0, Mat[i][1] = 0;
        cnt = 0, tot = 0;
    }

    bool dfs(int u) {
        if (Tim[u] == tot)
            return false;        
        Tim[u] = tot;
        for (int i = head[u], v; ~i; i = e[i].nxt) {
            v = e[i].v;
            if (!Mat[v][1] || dfs(Mat[v][1])) {
                Mat[v][1] = u, Mat[u][0] = v;
                return true;
            }
        }
        return false;
    }

    int calc() {
        int ans = 0;
        for (int i = 1; i <= m; i++)
            Mat[i][1] = 0;
        for (int i = 1; i <= n; i++)
            Tim[i] = 0, Mat[i][0] = 0;
        for (int i = n; i >= 1; i--) {
            tot++;
            ans += dfs(i);
        }
        return ans;
    }    
} Graph;

KM.

最小权最大匹配。

int n, m;
bool Vis[MAXN];
int Mat[MAXN], fa[MAXN];
LL w[MAXN][MAXN], Slack[MAXN], Val[MAXN][2];

void bfs(int S) {
    for(int i = 0; i <= n; i++) 
        Slack[i] = INF, Vis[i] = false;
    LL d;
    int pos = 0, p, u;
    for(Mat[pos] = S; Mat[pos]; pos = p) {
        Vis[pos] = true, u = Mat[pos], d = INF;
        for(int v = 1; v <= n; v++) {
            if(Vis[v])
                continue;
            if(Val[u][0] + Val[v][1] - w[u][v] < Slack[v]) {
                Slack[v] = Val[u][0] + Val[v][1] - w[u][v];
                fa[v] = pos;
            }
            if(Slack[v] < d) {
                d = Slack[v];
                p = v;
            }
        }
        for(int v = 0; v <= n; v++)
            if(Vis[v])
                Val[Mat[v]][0] -= d, Val[v][1] += d;
            else
                Slack[v] -= d;
    }
    for(; pos; pos = fa[pos])
        Mat[pos] = Mat[fa[pos]];
}

LL KM() {
    LL res = 0;
    for(int i = 1; i <= n; i++)
        bfs(i);
    for(int i = 1; i <= n; i++)
        res += w[Mat[i]][i];
    return res;
}
posted @ 2022-01-06 20:31  STrAduts  阅读(51)  评论(0)    收藏  举报