Cod sursa(job #3151535)

Utilizator Luca529Taschina Luca Luca529 Data 21 septembrie 2023 18:30:22
Problema Flux maxim de cost minim Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.68 kb
#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define MOD 1000000007
#define MAX 355
#define INF 1000000000

using namespace std;

int initial[MAX][MAX];
pair < int, int > h[MAX][MAX];
vector < int > v[MAX], a;
int dist[MAX], prec[MAX], r = 0;
bool viz[MAX];

queue < int > q;
priority_queue < pair < int, int >, vector < pair < int, int > >, greater < pair < int, int > > > qq;


int findingBottleNeck(int x);
void update(int x, int bottleNeck);

int main()
{
    FILE *input = fopen("fmcm.in", "r");
    ofstream cout ("fmcm.out");
    int n, m, s, t, x, y, c, z, bottleNeck;

    fscanf(input, "%d %d %d %d", &n, &m, &s, &t);
    //cin >> n >> m >> s >> t;
    for(int i = 1; i <= m; i++)
    {
        fscanf(input, "%d %d %d %d", &x, &y, &c, &z);
        //cin >> x >> y >> c >> z;
        v[x].pb(y), v[y].pb(x);
        initial[x][y] = z;
        h[x][y] = {c, z};
        h[y][x] = {0, -z};
    }

    // Rulam o data Bellman Ford, pentru a calcula vectorul dist.
    for(int i = 1; i <= n; i++) dist[i] = INF;
    dist[s] = 0, prec[s] = -1;

    q.push(s), viz[s] = true;
    while(!q.empty())
    {
        x = q.front(), q.pop(), viz[x] = false;
        for(int it:v[x])
        {
            if(h[x][it].first > 0 && dist[x] + h[x][it].second < dist[it])
            {
                dist[it] = dist[x] + h[x][it].second, prec[it] = x;
                if(!viz[it]) q.push(it), viz[it] = true;
            }
        }
    }

    // Calculam primul pas: F1 (costul minim pentru ca un flux de 1 sa circule de la s la t.)
    if(dist[t] != INF)
    {
        a.clear();
        bottleNeck = findingBottleNeck(t);
        //cout << bottleNeck << ' ';
        update(t,  bottleNeck);
        //update(t, 1);

        // Modificam costurile muchiilor a.i. nicio muchie sa nu mai aiba costul negativ.
        for(int i = 1; i <= n; i++)
            for(int it:v[i])
                h[i][it].second += dist[i] - dist[it];
    }


    // Calculam restul pasilor
    while(dist[t] != INF)
    {
        for (int i = 1; i <= n; i++) dist[i] = INF, viz[i] = false;
        dist[s] = 0, prec[s] = -1;

        qq.push({dist[s], s});
        while(!qq.empty())
        {
            pair < int, int > x = qq.top();
            qq.pop();

            if (!viz[x.second])
            {
                viz[x.second] = true;

                for (int it: v[x.second])
                    if (h[x.second][it].first > 0 && dist[x.second] + h[x.second][it].second < dist[it])
                    {
                        dist[it] = dist[x.second] + h[x.second][it].second, prec[it] = x.second;
                        qq.push({dist[it], it});
                    }

            }
        }

        if(dist[t] != INF)
        {
            a.clear();
            bottleNeck = findingBottleNeck(t);
            //cout << bottleNeck << ' ';
            update(t,  bottleNeck);
            //update(t, 1);

            // Modificam costurile muchiilor a.i. nicio muchie sa nu mai aiba costul negativ.
            for(int i = 1; i <= n; i++)
                for(int it:v[i])
                    h[i][it].second += dist[i] - dist[it];
        }
    }
    cout << r;

    return 0;
}

int findingBottleNeck(int x)
{
    int minn = 10001;
    while(prec[x] != -1)
    {
        minn = min(minn, h[prec[x]][x].first);
        x = prec[x];
    }

    return minn;
}

void update(int x, int bottleNeck)
{
    while(prec[x] != -1)
    {
        h[prec[x]][x].first -= bottleNeck, r += bottleNeck * initial[prec[x]][x];
        h[x][prec[x]].first += bottleNeck, r -= bottleNeck * initial[x][prec[x]];
        x = prec[x];
    }
}