Min-Cost Max-Flow

O(F·V·E) worst case

Maximum flow of minimum total cost: repeatedly push along the cheapest augmenting path, found with SPFA since reverse edges carry negative costs. Handles the standard assignment/transport reductions; for pure assignment the Hungarian template is faster.

// use it on

AtCoder Library Practice E

A grid pick problem that reduces to min-cost flow with row and column nodes. Build the network and call min_cost_flow.

// the code

struct MCMF {
    struct Edge { int to; long long cap, cost; };
    int n;
    vector<Edge> edges;
    vector<vector<int>> g;
    MCMF(int n) : n(n), g(n) {}
    void add_edge(int u, int v, long long cap, long long cost) {
        g[u].push_back(edges.size()); edges.push_back({v, cap, cost});
        g[v].push_back(edges.size()); edges.push_back({u, 0, -cost});
    }
    pair<long long, long long> min_cost_flow(int s, int t) {  // {flow, cost}
        const long long INF = LLONG_MAX / 4;
        long long flow = 0, cost = 0;
        while (true) {
            vector<long long> dist(n, INF);
            vector<int> pe(n, -1);
            vector<bool> inq(n, false);
            deque<int> q = {s};  // SPFA
            dist[s] = 0;
            while (!q.empty()) {
                int u = q.front();
                q.pop_front();
                inq[u] = false;
                for (int id : g[u]) {
                    auto& e = edges[id];
                    if (e.cap > 0 && dist[u] + e.cost < dist[e.to]) {
                        dist[e.to] = dist[u] + e.cost;
                        pe[e.to] = id;
                        if (!inq[e.to]) {
                            inq[e.to] = true;
                            q.push_back(e.to);
                        }
                    }
                }
            }
            if (dist[t] >= INF) break;
            long long push = INF;
            for (int v = t; v != s; v = edges[pe[v] ^ 1].to)
                push = min(push, edges[pe[v]].cap);
            for (int v = t; v != s; v = edges[pe[v] ^ 1].to) {
                edges[pe[v]].cap -= push;
                edges[pe[v] ^ 1].cap += push;
            }
            flow += push;
            cost += push * dist[t];
        }
        return {flow, cost};
    }
};