Cod sursa(job #1996261)

Utilizator Andrei1998Andrei Constantinescu Andrei1998 Data 30 iunie 2017 19:23:17
Problema Flux maxim de cost minim Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 4.92 kb
#include <fstream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <utility>
#include <queue>

using namespace std;


template <int NMAX, int MMAX>
class MaxFlowMinCost {
public:
    MaxFlowMinCost() { m = 0; }

    inline void setN(int _n) { n = _n; }
    inline void setS(int _s) { s = _s; }
    inline void setT(int _t) { t = _t; }

    inline int getN() { return n; }
    inline int getS() { return s; }
    inline int getT() { return t; }

    void clear() {
        m = 0;
        for (int i = 1; i <= n; ++ i)
            graph[i].clear();
    }

    void reset() {
        for (int i = 0; i < m; ++ i)
            edges[i].flow = 0;
    }

    void addEdge(int from, int to, int cap, int cost) {
        edges[m ++] = Edge(from, to, 0, cap, cost);
        edges[m ++] = Edge(to, from, 0, 0, -cost);

        graph[from].push_back(m - 2);
        graph[to].push_back(m - 1);
    }

    inline pair <int, int> computeFlow() {
        return JohnsonDinic();
    }
private:
    struct Edge {
        int from, to;
        int flow, cap, cost;

        Edge(int _from = 0, int _to = 0, int _flow = 0, int _cap = 0, int _cost = 0):
            from(_from), to(_to), flow(_flow), cap(_cap), cost(_cost) {}
        inline int other(int node) {
            return from ^ to ^ node;
        }
    };

    int n, m, s, t;

    vector <int> graph[NMAX];
    Edge edges[2 * MMAX];

    const int INF = 1E9;

    int potentials[NMAX];
    queue <int> q;
    bool inQueue[NMAX];
    void Bellman() {
        for (int i = 1; i <= n; ++ i) {
            inQueue[i] = false;
            potentials[i] = INF;
        }

        inQueue[s] = true;
        potentials[s] = 0;
        q.push(s);

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

            for (auto edge: graph[node]) {
                int other = edges[edge].other(node);
                int cost = edges[edge].cost;

                if (edges[edge].flow < edges[edge].cap && potentials[node] + cost < potentials[other]) {
                    potentials[other] = potentials[node] + cost;
                    if (!inQueue[other]) {
                        inQueue[other] = true;
                        q.push(other);
                    }
                }
            }
        }
    }

    int dist[NMAX];
    int father[NMAX];
    bool vis[NMAX];
    priority_queue <pair <int, int> > _queue;

    bool Dijkstra() {
        memset(vis, 0, (n + 1) * sizeof(bool));
        for (int i = 1; i <= n; ++ i)
            dist[i] = INF;

        dist[s] = 0;
        _queue.push(make_pair(0, s));

        int node;
        while (!_queue.empty()) {
            node = _queue.top().second;
            _queue.pop();

            if (vis[node])
                continue;
            vis[node] = true;

            for (auto edge: graph[node]) {
                int other = edges[edge].other(node);
                int cost = edges[edge].cost + potentials[node] - potentials[other];

                if (edges[edge].flow < edges[edge].cap && dist[node] + cost < dist[other]) {
                    dist[other] = dist[node] + cost;
                    father[other] = edge;
                    _queue.push(make_pair(-dist[other], other));
                }
            }
        }

        for (int i = 1; i <= n; ++ i)
            dist[i] += (potentials[i] - potentials[s]);

        return vis[t];
    }

    pair <int, int> JohnsonDinic() {
        memset(potentials, 0, (n + 1) * sizeof(int));
        Bellman();

        int flow = 0, cost = 0;
        while (Dijkstra()) {
            int node = t;
            int minimum = INF;
            int sum = 0;

            while (node != s) {
                minimum = min(minimum, edges[father[node]].cap - edges[father[node]].flow);
                sum += edges[father[node]].cost;
                node = edges[father[node]].other(node);
            }

            node = t;
            while (node != s) {
                edges[father[node]].flow += minimum;
                edges[father[node] ^ 1].flow -= minimum;
                node = edges[father[node]].other(node);
            }

            flow += minimum;
            cost += minimum * sum;

            memcpy(potentials, dist, (n + 1) * sizeof(int));
        }

        return make_pair(flow, cost);
    }
};

const int NMAX = 350 + 5;
const int MMAX = 12500 + 5;

MaxFlowMinCost <NMAX, MMAX> f;

int main()
{
    ifstream cin("fmcm.in");
    ofstream cout("fmcm.out");
    int n, m, s, t;
    cin >> n >> m >> s >> t;

    f.setN(n);
    f.setS(s);
    f.setT(t);

    while (m --) {
        int a, b, cap, cost;
        cin >> a >> b >> cap >> cost;

        f.addEdge(a, b, cap, cost);
    }

    pair <int, int> ans = f.computeFlow();
    cout << ans.second << '\n';
    return 0;
}