Cod sursa(job #2957661)

Utilizator mihairazvan03Dana Mihai mihairazvan03 Data 23 decembrie 2022 11:53:42
Problema Flux maxim Scor 70
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.43 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <climits>

//facem un ford fulkerson obisnuit. Complexitate O(mL); m = nr de muchii; L = capacitatea minima a uneti taieturi

using namespace std;
ifstream in("maxflow.in");
ofstream out("maxflow.out");

int n, m, fluxMaxim;
vector<vector<int>> ramas;
vector<int> visited, dad;
queue<int> coada;

bool construiesteDrum()
{
    int i, nodCurent;

    while(!coada.empty())
        coada.pop();

    for(i = 1; i <= n; i++)
    {
        dad[i] = 0;
        visited[i] = 0;
    }

    coada.push(1);         //pornim de la nodul 1 pt ca ala e nodul de start
    visited[1] = 1;

    while(!coada.empty())
    {
        nodCurent = coada.front();
        coada.pop();

        if (nodCurent == n)   //daca am ajuns la n care e destinatia inseamna ca am reusit sa creem un drum
            return true;

        for(i = 1; i <= n; i++)   //parcurgem toate nodurile si vedem daca se poate ajunge din nodul curent in respectivul nod (adica sa nu fie vizitat si sa mai avem capacitate ramasa)
            if(visited[i] == 0 && ramas[nodCurent][i] > 0)
            {
                visited[i] = 1;
                dad[i] = nodCurent;
                coada.push(i);
            }
    }

    return false;  //daca se ajunge aici inseamna ca if(nodCurent == n) nu a fost apelat, deci nu s-a ajuns pana la destinatie, deci nu am reusit sa creem un drum
}

void calculeazaFluxMax()
{
    int i, fiu, nodCurent, j, bootleNeck;
    vector<int> drum;

    while(construiesteDrum())    //daca nu mai gasim un drum ne oprim
    {
        for(i = 1; i < n; i++)   //incercam sa reconstruim drumurile
        {
            if(visited[i] == 1 && ramas[i][n] > 0)  //inseamna ca din nodul i la care suntem acuma s-a transportat o anumita cantitate in nodul final
            {
                fiu = i;
                drum.clear();      //daca nu facem asta ramane din forul anterior
                drum.push_back(n);
                drum.push_back(fiu);
                nodCurent = dad[fiu];

                while (nodCurent != 1)     //mergem inapoi pe traseu si reconstruim drumul
                {
                    drum.push_back(nodCurent);
                    nodCurent = dad[nodCurent];
                }

                drum.push_back(1);

                bootleNeck = INT_MAX;

                for(j = drum.size() - 1; j >= 1; j--)     //parcurgem pe invers pt ca noi in drum am pus elementele pornind de la destinatie spre start
                    bootleNeck = min(bootleNeck, ramas[drum[j]][drum[j - 1]]);

                fluxMaxim += bootleNeck;

                for(j = drum.size() - 1; j >= 1; j--)
                {
                    ramas[drum[j]][drum[j - 1]] -= bootleNeck;   //scadem capacitatea ramase pt drumurile prin care am trecut
                    ramas[drum[j - 1]][drum[j]] += bootleNeck;   //in cazul drumurilor reversed crestem aceasta capacitate
                }
            }
        }
    }
}

int main()
{
    int i, nod1, nod2, capacitate;

    in >> n >> m;
    ramas.resize(n + 1);
    visited.resize(n + 1);
    dad.resize(n + 1);

    for(i = 1; i <= n; i++)
        ramas[i].resize(n + 1, 0);

    for(i = 1; i <= m; i++)
    {
        in >> nod1 >> nod2 >> capacitate;
        ramas[nod1][nod2] = capacitate;
    }

    calculeazaFluxMax();

    out << fluxMaxim;

    return 0;
}