Cod sursa(job #2900917)

Utilizator redstonegamer22Andrei Ion redstonegamer22 Data 12 mai 2022 15:11:02
Problema Flux maxim de cost minim Scor 70
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.89 kb
#include <bits/stdc++.h>

using namespace std;

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

    vector<Edge> edges;
    vector<vector<int>> adj;
    int source, sink;
    const int INF = 2e9 + 7;

    vector<int> realdist, fakedist, dist;
    vector<int> prev, viz;

    MCMF(int _n) {
        source = _n + 3; sink = _n + 4;
        adj.resize(_n + 7);

        realdist.resize(_n + 7);
        fakedist.resize(_n + 7);
        dist.resize(_n + 7);

        prev.resize(_n + 7);
        viz.resize(_n + 7);
    }

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

    void make_source(int node) { add_edge(source, node, INF, 0); }
    void make_sink(int node) { add_edge(node, sink, INF, 0); }

    void bellman() {
        for(auto &e : dist) e = INF;

        vector<bool> inq(sink + 3);
        queue<int> q; q.push(source);
        dist[source] = 0;

        while(!q.empty()) {
            auto node = q.front(); q.pop();
            inq[node] = false;

            for(auto eid : adj[node]) {
                auto edge = edges[eid];

                if(edge.cap > edge.flow && dist[edge.to] > dist[node] + edge.cost) {
                    dist[edge.to] = dist[node] + edge.cost;
                    if(inq[edge.to] == false) {
                        q.push(edge.to); inq[edge.to] = true;
                    }
                }
            }
        }
    }

    bool dijkstra() {
        priority_queue<pair<int, int>> pq;
        for(auto &e : prev) e = -1;
        for(auto &e : viz) e = false;
        for(int i = 0; i < dist.size(); ++i) realdist[i] = dist[i];
        for(auto &e : fakedist) e = INF;

        dist[source] = fakedist[source] = 0;
        pq.push({ -0, source });

        while(!pq.empty()) {
            int node = pq.top().second; pq.pop();
            if(viz[node] == false) {
                viz[node] = true;

                for(auto eid : adj[node]) {
                    auto edge = edges[eid];
                    if(edge.cap > edge.flow && (prev[edge.to] == -1 || fakedist[node] + realdist[node] + edge.cost - realdist[edge.to] < fakedist[edge.to])) {
                        prev[edge.to] = eid ^ 1;
                        fakedist[edge.to] = fakedist[node] + realdist[node] + edge.cost - realdist[edge.to];
                        dist[edge.to] = dist[node] + edge.cost;
                        pq.push({ -fakedist[edge.to], edge.to });
                    }
                }
            }
        }

        return fakedist[sink] != INF;
    }

    pair<int64_t, int64_t> get_flow_cost() {
        int64_t flow = 0, cost = 0;

        bellman();

        while(dijkstra()) {
            int64_t cnt_flow = INF, cnt_cost = 0;
            for(int node = sink; node != source; node = edges[prev[node]].to) {
                auto edge = edges[prev[node] ^ 1];
                cnt_cost += edge.cost;
                cnt_flow = min(cnt_flow, (int64_t)edge.cap - edge.flow);
            }
            for(int node = sink; node != source; node = edges[prev[node]].to) {
                auto eid = prev[node] ^ 1;
                edges[eid].flow += cnt_flow;
                edges[eid ^ 1].flow -= cnt_flow;
            }

            flow += cnt_flow;
            cost += cnt_flow * cnt_cost;
        }

        return {flow, cost};
    }
};

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

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

    MCMF sol(n + 3);
    sol.make_source(s);
    sol.make_sink(d);
    for(int i = 0; i < m; i++) {
        int u, v, cap, cost; cin >> u >> v >> cap >> cost;
        sol.add_edge(u, v, cap, cost);
    }

    auto ans = sol.get_flow_cost();
    cerr << ans.first << " ";
    cout << ans.second << endl;

    return 0;
}