Cod sursa(job #3147036)

Utilizator vmnechitaNechita Vlad-Mihai vmnechita Data 23 august 2023 20:20:42
Problema Flux maxim de cost minim Scor 50
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.13 kb
// O(F_max * m * log n)
#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define MOD 1000000007
#define MAX 355
#define INF 1000000000

using namespace std;

pair < int, int > initial[MAX][MAX], h[MAX][MAX];
vector < int > v[MAX], a;
int dist[MAX], s;
bool viz[MAX], gasit;

void dfsForFindingBottleNeck(int x, int prec);
void dfs(int x, int prec, int bottleNeck);

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

    int n, m, t, x, y, c, z;

    cin >> n >> m >> s >> t;
    for(int i = 1; i <= m; i++)
    {
        cin >> x >> y >> c >> z;
        v[x].pb(y), v[y].pb(x);
        initial[x][y] = {c, 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;

    queue < int > q;
    q.push(s);
    while(!q.empty())
    {
        x = q.front(), q.pop();
        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;
                q.push(it);
            }
        }
    }

    // Calculam primul pas: F1 (costul minim pentru ca un flux de 1 sa circule de la s la t.)
    if(dist[t] != INF)
    {
        gasit = false;
        //a.clear();
        //dfsForFindingBottleNeck(t, -1);
        //cout << *min_element(a.begin(), a.end()) << ' ';
        //dfs(t, -1, *min_element(a.begin(), a.end()));
        dfs(t, -1, 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];


    priority_queue < pair < int, int >, vector < pair < int, int > >, greater < pair < int, int > > > qq;
    while(dist[t] != INF)
    {
        for (int i = 1; i <= n; i++) dist[i] = INF, viz[i] = false;
        dist[s] = 0;

        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;
                        qq.push({dist[it], it});
                    }
            }
        }

        if(dist[t] != INF)
        {
            gasit = false;
            //a.clear();
            //dfsForFindingBottleNeck(t, -1);
            //cout << *min_element(a.begin(), a.end()) << ' ';
            //dfs(t, -1, *min_element(a.begin(), a.end()));
            dfs(t, -1, 1);
        }

        for(int i = 1; i <= n; i++)
            for(int it:v[i])
                h[i][it].second += dist[i] - dist[it];
    }

    int r = 0;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            if(initial[i][j].second != 0)
                r += initial[i][j].second * (initial[i][j].first - h[i][j].first);

    cout << r;

    return 0;
}

void dfsForFindingBottleNeck(int x, int prec)
{
    if(x != s)
    {
        for(int it:v[x])
            if(it != prec && h[it][x].first >= 1 && dist[it] + h[it][x].second == dist[x])
            {
                a.pb(h[it][x].first);
                dfsForFindingBottleNeck(it, x);
                if(!gasit) a.pop_back();
                else break;
            }
    }
    else gasit = true;
}

void dfs(int x, int prec, int bottleNeck)
{
    if(x != s)
    {
        for(int it:v[x])
            if(it != prec && h[it][x].first >= bottleNeck && dist[it] + h[it][x].second == dist[x])
            {
                h[it][x].first -= bottleNeck;
                h[x][it].first += bottleNeck;
                dfs(it, x, bottleNeck);
                if(!gasit)
                {
                    h[it][x].first += bottleNeck;
                    h[x][it].first -= bottleNeck;
                }
                else break;
            }
    }
    else gasit = true;
}

/*
5 7 2 5
3 1 7 -1
1 4 3 0
3 4 3 -4
1 5 7 0
4 5 1 1
2 5 8 -3
2 3 4 -3
*/