Cod sursa(job #1740489)

Utilizator AlexandruValeanuAlexandru Valeanu AlexandruValeanu Data 11 august 2016 17:21:32
Problema Flux maxim de cost minim Scor 70
Compilator cpp Status done
Runda Arhiva educationala Marime 4.17 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>;

vector<int> G[MAX_N];

int capacity[MAX_N][MAX_N];
int flow[MAX_N][MAX_N];
int cost[MAX_N][MAX_N];

bool inQueue[MAX_N];
int dist[MAX_N];
int father[MAX_N];

int N, M;

void addEdge(int x, int y, int cap, int cst)
{
    G[x].push_back(y);
    capacity[x][y] += cap;
    cost[x][y] += cst;
}

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

    queue<int> Q;

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

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

        for (int son : G[node])
        {
            if (capacity[node][son] > flow[node][son] && dist[son] > dist[node] + cost[node][son])
            {
                dist[son] = dist[node] + cost[node][son];

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

}

void updateCosts()
{
    for (int i = 1; i <= N; ++i)
    {
        if (dist[i] != INF)
        {
            for (int son : G[i])
                if (dist[son] != INF)
                    cost[i][son] += dist[i] - dist[son];
        }
    }
}

bool diskstra(int S, int T)
{
    updateCosts();

    for (int i = 1; i <= N; ++i)
    {
        father[i] = 0;
        dist[i] = INF;
    }

    dist[S] = 0;
    father[S] = S;

    priority_queue<Pair, vector<Pair>, greater<Pair>> maxHeap;
    maxHeap.push({dist[S], S});

    while (!maxHeap.empty())
    {
        auto p = maxHeap.top();
        maxHeap.pop();

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

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

        for (int son : G[node])
        {
            if (capacity[node][son] > flow[node][son] && dist[son] > dist[node] + cost[node][son])
            {
                dist[son] = dist[node] + cost[node][son];
                father[son] = node;

                maxHeap.push({dist[son], son});
            }
        }
    }

    return dist[T] != INF;
}

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

    bellmanFord(S);
    totalDist = dist[T];

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

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

        node = T;

        while (node != S)
        {
            flow[ father[node] ][node] += fmin;
            flow[node][ father[node] ] -= fmin;
            node = father[node];
        }

        totalFlow += fmin;
        totalDist += dist[T];
        costTotalFlow += (long long)fmin * totalDist;
    }

    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 = 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;
}