Cod sursa(job #2963268)

Utilizator redstonegamer22Andrei Ion redstonegamer22 Data 10 ianuarie 2023 18:03:15
Problema Flux maxim de cost minim Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.3 kb
#include <bits/stdc++.h>

using namespace std;

#ifndef LOCAL
ifstream in("fmcm.in");
ofstream out("fmcm.out");
#define cin in
#define cout out
#endif // LOCAL

struct MCMF {
    struct Edge {
        int from, to, flow, cap, cost;
    };

    static const int buffer = 7;
    int n, source, sink;
    vector<Edge> edges;
    vector<vector<int>> edge_ids;
    vector<int> potential;
    vector<int> coming;

    MCMF(int _n, int _source, int _sink) {
        n = _n; source = _source; sink = _sink;
        edge_ids.resize(n + buffer);
        potential.resize(n + buffer);
        coming.resize(n + buffer);
    }

    void add_edge(int from, int to, int cap, int cost) {
        edge_ids[from].push_back(edges.size()); edges.push_back({from, to, 0, cap, cost});
        edge_ids[to].push_back(edges.size()); edges.push_back({to, from, 0, 0, -cost});
    }

    void bellman_ford() {
        vector<int> dist(n + buffer, 0);

        for(int i = 0; i < n + buffer; i++) {
            for(int i = 0; i < edges.size(); i += 2) {
                const auto& ed = edges[i];
                dist[ed.to] = min(dist[ed.to], dist[ed.from] + ed.cost);
            }
        }

        potential = dist;
    }

    bool dijkstra() {
        const int INF = 1e9;
        vector<int> dist(n + buffer, INF);
        dist[source] = 0;

        priority_queue<pair<int, int>> pq;
        pq.push({-dist[source], source});

        while(!pq.empty()) {
            auto cnt = pq.top(); pq.pop();

            if(dist[cnt.second] != -cnt.first) continue;

            for(auto eid : edge_ids[cnt.second]) {
                const auto &ed = edges[eid];
                if(ed.flow == ed.cap) continue;

                if(dist[ed.to] > dist[ed.from] + (ed.cost + potential[ed.from] - potential[ed.to])) {
                    dist[ed.to] = dist[ed.from] + (ed.cost + potential[ed.from] - potential[ed.to]);
                    coming[ed.to] = eid;
                    pq.push({-dist[ed.to], ed.to});
                }
            }
        }

        potential = dist;
        return dist[sink] != INF;
    }

    int64_t flow = 0, cost = 0;

    void compute() {
        for(auto &e : edges) e.flow = 0;
        flow = 0; cost = 0;

        bellman_ford();

        while(dijkstra()) {
            int cnt_flow = 1e9;

            for(int x = sink; x != source; x = edges[coming[x]].from) {
                cnt_flow = min(cnt_flow, edges[coming[x]].cap - edges[coming[x]].flow);
            }
            flow += cnt_flow;

            for(int x = sink; x != source; x = edges[coming[x]].from) {
                edges[coming[x] ^ 0].flow += cnt_flow;
                edges[coming[x] ^ 1].flow -= cnt_flow;

                cost += 1LL * edges[coming[x]].cost * cnt_flow;
            }
        }
    }

    int64_t max_flow() {
        compute(); return flow;
    }

    int64_t min_cost() {
        compute(); return cost;
    }
};

int main() {
    int n, m, s, d; cin >> n >> m >> s >> d;
    MCMF mcmf(n, s, d);

    for(int i = 0; i < m; i++) {
        int x, y, cap, cost; cin >> x >> y >> cap >> cost;
        mcmf.add_edge(x, y, cap, cost);
    }

    #ifdef LOCAL
        cerr << mcmf.max_flow() << endl;
    #endif // LOCAL
    cout << mcmf.min_cost() << endl;
}