Cod sursa(job #2959560)

Utilizator liviu_gheorghe1234Liviu Gheorghe liviu_gheorghe1234 Data 1 ianuarie 2023 14:52:35
Problema Taramul Nicaieri Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 7.76 kb
#include <iostream>
#include <fstream>
#include <queue>
#include <vector>
#define MAX_SIZE 200

using namespace std;

int L, R, nrNoduri, x, y;
vector<int> adjList[MAX_SIZE];

// Matrice ce retine capacitatea maxima pentru fiecare muchie in parte

int C[MAX_SIZE + 1][MAX_SIZE + 1];

// Matrice ce retine fluxul curent pentru fiecare muchie in parte

int F[MAX_SIZE + 1][MAX_SIZE + 1];

int D_Extern[MAX_SIZE + 1];
int D_Intern[MAX_SIZE + 1];

vector<pair<int, int>> drumuri = vector<pair<int, int>>(); 

int main() {

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

    // Se citesc cardinanul multimii L, resp cardinalul multimii R si numarul de muchii

    // Se citeste N, numarul de noduri
    fin >> nrNoduri; 

    L = nrNoduri;
    R = nrNoduri;


    // Trebuie sa adaugam un nod sursa pe care sa il legam de toate nodurile din L (pt ca nodurile din L incep de la 1, sursa va fi 0) 
    int S = 0;
    // Trebuie sa adaugam un nod destinatie pe care sa il legam de toate nodurile din R (cum nodurile din L si R sunt in numar de L + R si sunt indexate de la 1, trebuie sa punem destinatia pe pozitia L + R + 1)  
    int D = L + R + 1;

    // Se citesc gradele (extern respectiv intern)

    for(int i = 1; i <= nrNoduri; ++i) {
    
        fin >> x >> y;

        D_Extern[i] = x;
        D_Intern[i] = y;


        // Adaugam muchie intre sursa si fiecare nod, care va avea capacitatea egala cu gradul de iesire

        adjList[0].push_back(i);


        // Adaugam si muchia inversa, graf rezidual
        adjList[i].push_back(0);


        C[0][i] = x;


        // Adaugam muchie intre fiecare nod si destinatie, care va avea capacitatea egala cu gradul de intrare 

        adjList[i+L].push_back(D);
        C[i+L][D] = y;

        // Adaugam si muchia inversa, graf rezidual
        adjList[D].push_back(i+L);    
    }


    // Trebuie sa adaugam muchie de capacitate 1 intre nodurile din L si cele din R
  
    for(int i = 1; i <= nrNoduri; i++) {
        for(int j = 1; j <= nrNoduri; j++) {
            if(i==j) {
                continue;
            }

            adjList[i].push_back(j+L);
            // Adaugam si muchia inversa, graf rezidual
            adjList[j+L].push_back(i);
            C[i][j+L] = 1;
        }
    }

    //cout << "Destinatia este " << D << "\n";

    // Daca am gasit sau nu un path de ameliorare, ne ajuta sa stim cand ne oprin din a face BFS pe graful rezidual 

    bool augumentationPathFound = false;

    // Coada ce va fi folosita pentru parcurgerea BF

    queue<int> q;

    // Vector ce va retine daca un nod este vizitat sau nu in cadrul parcurgerii

    vector<bool> visited;

    // Vectorul de tati al arborelui generat de BFS 

    vector<int> parent; 

    // Daca am ajuns la nodul destinatie in BFS 

    bool destinationReched; 

    // Variabila ce va retine la final flow-ul maxim si va reprezenta suma flow-urilor de pe toate drumurile de ameliorare gasite

    int totalFlow = 0;

    do {

        // Pentru fiecare iteratie a BFS-ului trebuie sa resetam coada, vectorul visited, vectorul de tati si destinationReached

        q = queue<int>();
        visited = vector<bool>(L+R+1, false);
        parent = vector<int>(L+R+1, -1);
        destinationReched = false;

        // Incepem prin a introduce in coada nodul de start

        q.push(S);

        // Cat timp coada nu este vida

        while(!q.empty() && !destinationReched) {

            // Scoatem cel mai vechi nod din coada si il marcam ca si vizitat

            auto currentNode = q.front();
            q.pop();
            visited[currentNode] = true;

            // Trecem prin fiecare dintre nodurile vecine cu nodul curent

            for(int j = 0; j < adjList[currentNode].size(); j++) {
                auto currentNeighbor = adjList[currentNode][j];

                // Daca vecinul nu a fost inca vizitat si catre el capacitatea reziduala este mai mare decat 0 (capacitate - flux), atunci adaugam nodul in coada 
                
                if(!visited[currentNeighbor] && C[currentNode][currentNeighbor] - F[currentNode][currentNeighbor] > 0) {
                    q.push(currentNeighbor);

                    // Marcam si nodul vecin ca fiind vizitat 
                    visited[currentNeighbor] = true;

                    // Actualizam parintele nodului vecin (care este nodul curent)

                    parent[currentNeighbor] = currentNode;

                    // Daca am ajuns cumva la nodul destinatie, atunci oprim BFS-ul

                    if(currentNeighbor == D) {
                        destinationReched = true;
                        break;
                    }
                }
            }
        }

        if(destinationReched) {
            // cout << "S-a gasit un path de ameliorare vectorul de tati este: ";
            // for(auto x: parent) {
            //     cout << x << " ";
            // }


            //cout << " , iar muchiile ce compun path-ul sunt: ";
            // Daca am gasit un drum de ameliorare, atunci trebuie sa il reconstruim din vectorul de tati si sa actualizam fluxul muchiilor ce fac parte din acel drum


            int cNode = D;
            int pNode = D;
            int bottleneck = -1; 



            bool edgeFound = false;
            pair<int, int> cPair = pair<int, int>();

            while(true) {
                if(pNode == -1) {
                    break;
                }

                if(pNode != -1 && pNode != cNode) {


                    // Daca parent node-ul este egal cu 0, inseamna ca cNode (nodul curent) face parte din multimea L.

                    cout << "(" << pNode << " " << cNode << ") ";

                    if(pNode == 0) {
                        cPair.first = cNode;
                    }


                    // Daca curent node-ul este egal cu destinatia (L+R+1), atunci inseamna ca pNode (parent node-ul) face parte din multimea R

                    if(cNode == L + R + 1) {
                        cPair.second = pNode - L;
                    } 
                    

                    if(bottleneck == -1 || C[pNode][cNode] - F[pNode][cNode] < bottleneck) {
                        bottleneck = C[pNode][cNode] - F[pNode][cNode];
                    }
                }

                cNode = pNode;

                pNode = parent[pNode];
            }

            printf("[%d %d] ", cPair.first, cPair.second);

            cout << "Pt path-ul de mai sus fluxul maxim pe care il putem adauga este egal cu " << bottleneck << "\n";

            cNode = D;
            pNode = D;

            while(true) {
                if(pNode == -1) {
                    break;
                }

                if(pNode != -1 && pNode != cNode) {
                    // Scadem bottleneck-ul din muchia din graful initial si adaugam la muchia inversa bottleneck-ul cu semn schimbat
                    F[pNode][cNode] += bottleneck;
                    F[cNode][pNode] -= bottleneck;       
                }

                cNode = pNode;

                pNode = parent[pNode];
            }

            totalFlow += bottleneck;

            cout << "\n";
            augumentationPathFound = true;
        } else {
            augumentationPathFound = false;
        }

    } while(augumentationPathFound);


    //cout << "Flow-ul maxim este " << totalFlow; 
    fout << totalFlow << "\n";


    cout << "==============================";

    for(int i = 1; i <= L; i++) {
        for(int j = L+1; j <= L + R; j++) {
            if(F[i][j] == C[i][j] && F[i][j] == 1) {
                fout << i << " "<< j - L << "\n";
            }
        }
    }

    return 0;
}