Cod sursa(job #3190280)

Utilizator andrei_l20031Legian Andrei andrei_l20031 Data 7 ianuarie 2024 14:08:53
Problema Taramul Nicaieri Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.33 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <climits>

using namespace std;

ifstream in("harta.in");
ofstream out("harta.out");

bool BFS(int NodSursa, int nodDestinatie, vector <int>& tati, vector<vector<int>>& vecini, int N, vector<vector<int>> flux, vector<vector<int>> capacitate) {
    queue <int> coada;
    coada.push(NodSursa);

    tati[NodSursa] = 0;
    int drum = false;

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

        for (auto vecin: vecini[nodCurent]) {
            /// daca nodul este nevizitat si muchia nu a fost folosit de alt drum (nu are fluxul la capacitatea maxima)
            if (tati[vecin] == -1 && flux[nodCurent][vecin] < capacitate[nodCurent][vecin]) {
                coada.push(vecin);
                tati[vecin] = nodCurent;

                /// verific daca am ajuns la nodul destinatie
                if (vecin == nodDestinatie) {
                    drum = true;
                    break;
                }
            }
        }
    }
    return drum;
}


int main() {
    int nrNoduri;
    in >> nrNoduri;

    int nodSursa = 2 * nrNoduri + 1, nodDestinatie = 2 * nrNoduri + 2;

    /// in vectorul vecini retin toate posibilile noduri adiacente ale fiecarui nod
    vector<vector<int>> vecini(2 * nrNoduri + 3);
    /// in vectorul capacitate retin capacitatea maxima pe care o poate avea fiecare muchie
    vector<vector<int>> capacitate(2 * nrNoduri + 3, vector<int>(2 * nrNoduri + 3, 0));

    /// voi folosi 2 "seturi" de noduri: de la 1 la N si de la N + 1 la 2 * N
    /// nodurile 1..N reprezinta aceleasi noduri ca N + 1..2 * N (1 == N + 1, 2 == N + 2 ...)
    /// primul set de noduri (1..N) sunt noduri din care se pleaca spre nodul destinatie
    /// al doilea set de noduri (N + 1 .. 2 * N) sunt noduri din care se ajunge in nodul sursa

    for (int i = 1; i <= nrNoduri; i++) {
        int gradInterior, gradExterior;
        in >> gradExterior >> gradInterior;

        capacitate[nodSursa][i] = gradExterior;
        vecini[i].push_back(nodSursa);
        vecini[nodSursa].push_back(i);

        capacitate[i + nrNoduri][nodDestinatie] = gradInterior;
        vecini[i + nrNoduri].push_back(nodDestinatie);
        vecini[nodDestinatie].push_back(i + nrNoduri);
    }

    for (int i = 1; i <= nrNoduri; i++) {
        for (int j = nrNoduri + 1; j <= 2 * nrNoduri; j++) {
            /// daca nu se formeaza un ciclu (de la 1 la N + 1) atunci ar putea exista o muchie intre cele 2 noduri
            if (j - nrNoduri != i) {
                capacitate[i][j] = 1;
                vecini[i].push_back(j);
                vecini[j].push_back(i);
            }
        }
    }

    /// !!! folosim alg Edmonds-Karp !!!


    vector<vector<int>> flux(2 * nrNoduri + 3, vector<int>(2 * nrNoduri + 3, 0));
    int fluxTotal = 0;

    bool drum = true;
    while (drum) {
        /// folosesc un vector de tati pentru a reconstitui drumul gasit
        vector<int> tati(2 * nrNoduri + 3, -1);

        drum = BFS(nodSursa, nodDestinatie, tati, vecini, nrNoduri, flux, capacitate);
        if (drum) {
            /// refac drumul si determin bottleneck-ul drumului
            int bottleneck = INT_MAX;
            int nodActual = nodDestinatie;

            while (tati[nodActual] != 0) {
                int tata = tati[nodActual];
                if(capacitate[tata][nodActual] - flux[tata][nodActual] < bottleneck)
                    bottleneck = capacitate[tata][nodActual] - flux[tata][nodActual];
                nodActual = tata;
            }

            /// actualizez fluxul maxim
            fluxTotal += bottleneck;

            /// actualizez fluxul fiecarei muchii din drumul gasit
            nodActual = nodDestinatie;
            while (tati[nodActual] != 0) {
                int tata = tati[nodActual];
                flux[tata][nodActual] += bottleneck;
                flux[nodActual][tata] -= bottleneck;
                nodActual = tata;
            }
        }
    }

    out << fluxTotal << endl;
    for (int i = 1; i <= nrNoduri; i++) {
        for (int j = nrNoduri + 1; j <= 2 * nrNoduri; j++) {
            if (flux[i][j] > 0) {
                out << i << " " << j - nrNoduri << endl;
            }
        }
    }

    return 0;
}