Cod sursa(job #1742278)

Utilizator AlexandruValeanuAlexandru Valeanu AlexandruValeanu Data 16 august 2016 09:33:33
Problema Flux maxim de cost minim Scor 70
Compilator cpp Status done
Runda Arhiva educationala Marime 4.83 kb
#include <bits/stdc++.h>

using namespace std;

class MinCostMaxFlow
{
private:

    static const int INF = numeric_limits<int>::max();

    class Edge
    {
    public:

        int flow;
        int capacity;
        int cost;

        int node;
        int next;

        Edge(int f, int cap, int cst, int _node, int _next) : flow(f), capacity(cap),
            cost(cst), node(_node), next(_next) {
        }
    };

    class Node
    {
    public:

        int distance;
        int node;

        Node(int d, int _node) : distance(d), node(_node){
        }

        bool operator < (const Node &X) const
        {
            return distance > X.distance;
        }
    };

    vector<Edge> graph;
    vector<int> head, father, pointer;
    vector<int> oldDist, realDist, newDist;
    int N;

    void bellmanFord(int source)
    {
        fill(oldDist.begin(), oldDist.end(), INF);

        vector<bool> inQueue(N, false);
        queue<int> Q;

        Q.push(source);
        inQueue[source] = true;
        oldDist[source] = 0;

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

            for (int p = head[node]; p != NIL; p = graph[p].next)
            {
                Edge &e = graph[p];

                if (e.flow < e.capacity && oldDist[e.node] > oldDist[node] + e.cost)
                {
                    oldDist[e.node] = oldDist[node] + e.cost;

                    if (!inQueue[e.node])
                    {
                        inQueue[e.node] = true;
                        Q.push(e.node);
                    }
                }
            }
        }
    }

    bool dijkstra(int S, int T)
    {
        fill(newDist.begin(), newDist.end(), INF);
        fill(realDist.begin(), realDist.end(), INF);
        fill(father.begin(), father.end(), NIL);
        fill(pointer.begin(), pointer.end(), NIL);

        priority_queue<Node> minHeap;
        father[S] = S;
        realDist[S] = newDist[S] = 0;
        minHeap.push({0, S});

        while (!minHeap.empty())
        {
            Node _node = minHeap.top();
            minHeap.pop();

            int node = _node.node;

            if (newDist[node] != _node.distance)
                continue;

            for (int p = head[node]; p != NIL; p = graph[p].next)
            {
                Edge &e = graph[p];
                int son = e.node;

                int new_distance = oldDist[node] - oldDist[son] + newDist[node] + e.cost;

                if (e.flow < e.capacity && newDist[son] > new_distance)
                {
                    newDist[son] = new_distance;
                    realDist[son] = realDist[node] + e.cost;

                    pointer[son] = p;
                    father[son] = node;

                    minHeap.push({newDist[son], son});
                }
            }
        }

        copy(realDist.begin(), realDist.end(), oldDist.begin());

        return realDist[T] != INF;
    }

public:

    static const int NIL;

    MinCostMaxFlow(int _N) : N(_N)
    {
        head.resize(N, NIL);
        father.resize(N);
        pointer.resize(N);
        oldDist.resize(N);
        realDist.resize(N);
        newDist.resize(N);
    }

    void addEdge(int from, int to, int capacity, int cost)
    {
        from--; to--;

        graph.push_back(Edge(0, capacity, cost, to, head[from]));
        head[from] = graph.size() - 1;
    }

    void addDoubleEdge(int from, int to, int capacity, int cost)
    {
        addEdge(from, to, capacity, cost);
        addEdge(to, from, 0, -cost);
    }

    pair<int,int> minCostMaxFlow(int S, int T)
    {
        S--; T--;
        assert(0 <= S && 0 <= T && S < N && T < N);
        assert(S != T);

        int totalFlow = 0;
        int costTotalFlow = 0;

        bellmanFord(S);

        while (dijkstra(S, T))
        {
            int fmin = INF;
            int node = T;

            while (node != S)
            {
                fmin = min(fmin, graph[pointer[node]].capacity - graph[pointer[node]].flow);
                node = father[node];
            }

            node = T;

            while (node != S)
            {
                graph[pointer[node]].flow += fmin;
                graph[pointer[node] ^ 1].flow -= fmin;
                node = father[node];
            }

            totalFlow += fmin;
            costTotalFlow += fmin * realDist[T];
        }

        return make_pair(totalFlow, costTotalFlow);
    }
};

const int MinCostMaxFlow::NIL = -1;

int main()
{
    ifstream in("fmcm.in");
    ofstream out("fmcm.out");

    int N, M, S, T;
    in >> N >> M >> S >> T;

    MinCostMaxFlow MCMF(N);

    for (int i = 0; i < M; ++i)
    {
        int x, y, capacity, cost;
        in >> x >> y >> capacity >> cost;

        MCMF.addDoubleEdge(x, y, capacity, cost);
    }

    auto p = MCMF.minCostMaxFlow(S, T);
    out << p.second << endl;

    return 0;
}