Cod sursa(job #1740518)

Utilizator AlexandruValeanuAlexandru Valeanu AlexandruValeanu Data 11 august 2016 17:59:41
Problema Flux maxim de cost minim Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 4.97 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;
}
///---------------------------------------------------

constexpr int MAX_N = 350 + 1;
constexpr int MAX_M = 12500 + 1;
constexpr int INF = numeric_limits<int>::max();

using Pair = pair<int,int>;

template<typename T>
class MinHeap
{
private:
    vector<T> heap;

public:

    MinHeap() : heap(){
    }

    void push(const T &p)
    {
        heap.emplace_back(p);
        push_heap(heap.begin(), heap.end(), greater<T>());
    }

    T top() const
    {
        return heap.front();
    }

    void pop()
    {
        pop_heap(heap.begin(), heap.end(), greater<T>());
        heap.pop_back();
    }

    bool empty() const
    {
        return heap.empty();
    }
};

constexpr int NIL = -1;

struct Edge
{
    int capacity;
    int flow;
    int cost;

    int node;
    int urm;
};

Edge G[2 * MAX_M];
int head[MAX_N];
int pointer[MAX_N];

bool inQueue[MAX_N];
int oldDist[MAX_N], newDist[MAX_N], realDist[MAX_N];
int father[MAX_N];

int N, M;
int counter;

void addEdge(int x, int y, int cap, int cst)
{
    G[counter] = {cap, 0, cst, y, head[x]};
    head[x] = counter++;
}

void bellmanFord(int S)
{
    for (int i = 1; i <= N; ++i)
    {
        oldDist[i] = INF;
        inQueue[i] = false;
    }

    queue<int> Q;

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

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

        for (int p = head[node]; p != NIL; p = G[p].urm)
        {
            int capacity = G[p].capacity;
            int flow = G[p].flow;
            int son = G[p].node;
            int cost = G[p].cost;

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

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

}

bool diskstra(int S, int T)
{
    for (int i = 1; i <= N; ++i)
    {
        father[i] = 0;
        newDist[i] = INF;
        realDist[i] = INF;
        pointer[i] = NIL;
    }

    newDist[S] = 0;
    realDist[S] = 0;
    father[S] = S;

    priority_queue<Pair,vector<Pair>,greater<Pair>> minHeap;
    minHeap.push({0, S});

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

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

        if (d != newDist[node])
            continue;

        for (int p = head[node]; p != NIL; p = G[p].urm)
        {
            int capacity = G[p].capacity;
            int flow = G[p].flow;
            int son = G[p].node;
            int cost = G[p].cost;

            int new_d = oldDist[node] - oldDist[son] + cost + newDist[node];

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

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

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

    memcpy(oldDist, realDist, sizeof(realDist));

    return newDist[T] != INF;
}

pair<int, int> minCostMaxFlow(int S, int T)
{
    int totalFlow = 0;
    int costTotalFlow = 0;

    bellmanFord(S);

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

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

        node = T;

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

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

    return {totalFlow, costTotalFlow};
}

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

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

    for (int i = 1; i <= N; ++i)
        head[i] = NIL;

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

        addEdge(x, y, cap, cst);
        addEdge(y, x, 0, -cst);
    }

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

    return 0;
}