Cod sursa(job #1740775)

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

using namespace std;


///---------------------------------------------------
const int BUFFER_SIZE = (1 << 16);
char buffer[BUFFER_SIZE];
int position = BUFFER_SIZE;

inline char getChar()
{
    if ( position == BUFFER_SIZE )
    {
        position = 0;
        fread(buffer, BUFFER_SIZE, 1, stdin);
    }

    return buffer[position++];
}

inline int getInt()
{
    register int a = 0;
    char ch;
    int sgn = 1;

    do
    {
        ch = getChar();

    } while ( !isdigit(ch) && ch != '-' );

    if ( ch == '-' )
    {
        sgn = -1;
        ch = getChar();
    }

    do
    {
        a = (a << 3) + (a << 1) + ch - '0';
        ch = getChar();

    } while ( isdigit(ch) );

    return a * sgn;
}
///---------------------------------------------------

class MinCostMaxFlow
{
private:

    using Pair = pair<int,int>;

    static const int NIL;
    static const int INF;

    class Edge
    {
    public:

        int flow;
        int capacity;
        int cost;

        int node;
        int next;

        Edge(int flow, int capacity, int cost, int node, int next)
        {
            this->flow = flow;
            this->capacity = capacity;
            this->cost = cost;
            this->node = node;
            this->next = next;
        }
    };

    int N;

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

    void bellmanFord(int S)
    {
        vector<bool> inQueue(N, false);
        fill(oldDist.begin(), oldDist.end(), INF);

        queue<int> Q;
        Q.push(S);
        inQueue[S] = true;
        oldDist[S] = 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];
                int son = e.node;

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

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

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

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

        while (!minHeap.empty())
        {
            auto pii = minHeap.top();
            minHeap.pop();

            int node = pii.second;
            int d = pii.first;

            if (newDist[node] != d)
                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] + e.cost + newDist[node];

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

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

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

        for (int i = 0; i < N; ++i)
            oldDist[i] = realDist[i];

        return realDist[T] != INF;
    }

public:

    MinCostMaxFlow(int _N) : N(_N), graph(), head(), father(), pointer(),
        realDist(), oldDist(), newDist() {

            head.resize(N, NIL);
            father.resize(N);
            pointer.resize(N);
            realDist.resize(N);
            oldDist.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 x, int y, int capacity, int cost)
    {
        addEdge(x, y, capacity, cost);
        addEdge(y, x, 0, -cost);
    }

    pair<int,int> minCostMaxFlow(int S, int T)
    {
        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;
const int MinCostMaxFlow::INF = numeric_limits<int>::max();

int main()
{
    freopen("fmcm.in", "r", stdin);
    freopen("fmcm.out", "w", stdout);

    int N, M, S, T;
    N = getInt();
    M = getInt();
    S = getInt();
    T = getInt();

    MinCostMaxFlow MCMF(N);

    for (int i = 0; i < M; ++i)
    {
        int x, y, cap, cst;
        x = getInt();
        y = getInt();
        cap = getInt();
        cst = getInt();

        MCMF.addDoubleEdge(x, y, cap, cst);
    }

    printf("%d\n", MCMF.minCostMaxFlow(S, T).second);

    return 0;
}