Cod sursa(job #2795970)

Utilizator MihaelaDanilaDanila Mihaela MihaelaDanila Data 7 noiembrie 2021 12:42:35
Problema Componente tare conexe Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 8.83 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <stack>
#include <unordered_set>

using namespace std;

int nodSursa;
int distante[100001];
vector<unordered_set<int>> componenteBiconexe;
vector<int> vizPasi;
vector<int> nivelMinimIntoarcere;
stack<pair <int, int>> StivaMuchiiComponentaBiconexaCurenta;
vector<vector<int>> ComponenteTareConexe;
stack<int> StivaComponentaTareConexaCurenta;
vector<int> isInStiva;
vector<int> arrivalTime;
vector<int> lowLinkValue;
int arrivalTimeCurent;

class Graf {
private:
    int m_nrNoduri;
    vector<vector<int>> m_listAdiacenta;
    vector<int> viz;
public:
    void citire(){
        ifstream f("../ctc.in");
        vector<int> aux;
        int nrMuchii;

        f>>this->m_nrNoduri;
        this->m_listAdiacenta.assign(this->m_nrNoduri + 1, aux);

        f>>nrMuchii;

        for(int i=0; i<nrMuchii; i++){
            int x,y;
            f>>x>>y;
            this->m_listAdiacenta[x].push_back(y);
        }

        viz.assign(this->m_nrNoduri + 1, 0);
    }

    void prelucrare(int nod, int x){
        //cout<<nod<<"\n";
        distante[nod] = distante[x] + 1;
    }

    void BFS(int nod){
        int curent;
        queue<int> coada;
        int viz[this->m_nrNoduri+1];
        for(int i=1; i<=m_nrNoduri; i++){
            viz[i] = 0;
        }

        coada.push(nod);
        viz[nod] = 1;
        prelucrare(nod, nod);

        while(!coada.empty()){
            curent = coada.front();
            for(int i=0; i < this->m_listAdiacenta[curent].size(); i++){
                if(viz[this->m_listAdiacenta[curent][i]] == 0){
                    coada.push(this->m_listAdiacenta[curent][i]);
                    prelucrare(coada.back(),curent);
                    viz[this->m_listAdiacenta[curent][i]] = 1;
                }
            }
            coada.pop();
        }

    }
/*
    void prelucrareDFS(int nod){
        cout<<nod<<endl;
    }
*/
    void DFS(int nod){
        //prelucrareDFS(nod);

        viz[nod] = 1;

        for(int i=0; i<this->m_listAdiacenta[nod].size(); i++){
            if(viz[this->m_listAdiacenta[nod][i]] == 0){
                DFS(this->m_listAdiacenta[nod][i]);
            }
        }
    }

    void afisDrumuri() {
        ofstream g("../bfs.out");
        for(int i=1; i <= this->m_nrNoduri; i++){
            g<<distante[i] - 1<<" ";
        }
    }

    void DFSBiconexe(int nodCurent, int precedent, int pas){
        //marcam ca vizitat nodul curent
        vizPasi[nodCurent] = pas;

        //momentan nivelul minim de intoarcere e nivelul curent, adica pasul
        nivelMinimIntoarcere[nodCurent] = pas;

        //parcurgem vecinii nodului curent
        for(int i=0; i<this->m_listAdiacenta[nodCurent].size(); i++){
            int vecinCurent = this->m_listAdiacenta[nodCurent][i];
            if(vecinCurent != precedent){
                //verificam pe ce fel de muchie suntem
                //daca vecinul curent a mai fost vizitat inseamna ca am dat de o muchie de intoarcere, altfel suntem pe o muchie in jos
                if(vizPasi[vecinCurent] == -1){
                    //am dat de o noua muchie din componenta biconexa curenta, asa ca o adaugam in stiva
                    StivaMuchiiComponentaBiconexaCurenta.push(make_pair(nodCurent, vecinCurent));
                    //apelam DFS pentru vecinul curent
                    DFSBiconexe(vecinCurent, nodCurent, pas + 1);
                    //verificam daca atunci cand ne am dus mai departe in graf
                    // am dat de o muchie de intoarcere care ne duce mai sus decat ne ducea nodul acesta inainte
                    if(nivelMinimIntoarcere[nodCurent] > nivelMinimIntoarcere[vecinCurent]){
                        nivelMinimIntoarcere[nodCurent] = nivelMinimIntoarcere[vecinCurent];
                    }
                    //verificam daca am ajuns la finalul componentei biconexe
                    if(nivelMinimIntoarcere[vecinCurent] >= vizPasi[nodCurent]){
                        //trebuie sa adaugam noua componenta biconexa in vectorul de componenete biconexe
                        //si sa golim stiva cu muchiile componentei biconexe curente
                        unordered_set<int> aux;
                        int aux1, aux2;
                        do{
                            aux1 = StivaMuchiiComponentaBiconexaCurenta.top().first;
                            aux2 = StivaMuchiiComponentaBiconexaCurenta.top().second;
                            aux.insert(aux1);
                            aux.insert(aux2);
                            StivaMuchiiComponentaBiconexaCurenta.pop();
                        } while (aux1 != nodCurent || aux2 != vecinCurent);
                        componenteBiconexe.push_back(aux);
                    }
                }else{
                    //avem o muchie de intoarcere, trebuie sa verificam daca nu cumva duce mai sus
                    if(nivelMinimIntoarcere[nodCurent] > vizPasi[vecinCurent]){
                        nivelMinimIntoarcere[nodCurent] = vizPasi[vecinCurent];
                    }
                }
            }
        }
    }

    void afisComponenteBiconexe(){
        ofstream g("../biconex.out");

        vizPasi.assign(this->m_nrNoduri + 1, -1);
        nivelMinimIntoarcere.resize(this->m_nrNoduri + 1);

        DFSBiconexe(1,0,0);

        g<<componenteBiconexe.size()<<"\n";
        for(int i=0; i<componenteBiconexe.size(); i++){
            for(unordered_set<int>::iterator it = componenteBiconexe[i].begin(); it != componenteBiconexe[i].end(); it++){
                g<<*it<<" ";
            }
            g<<"\n";
        }
    }

    void tarjan(int nod){
        //adaugam nodul in componenta tare conexa curenta, adica in StivaComponentaTareConexaCurenta
        StivaComponentaTareConexaCurenta.push(nod);
        //marcam nodul ca facand parte din componenta tare conexa curenta prin vectorul isInStiva
        isInStiva[nod] = 1;
        //marcam nodul ca vizitat, atribuindu-i chiar timpul de ajungere
        arrivalTime[nod] = arrivalTimeCurent;
        //valoarea low Link momentan este tot nivelul nodului curent
        lowLinkValue[nod] = arrivalTimeCurent;
        //marim timpul de ajungere pentru urmatorul pas
        arrivalTimeCurent++;
        //parcurgem vecinii nodului curent, facand un DFS
        for(int i=0; i<this->m_listAdiacenta[nod].size(); i++){
            int vecinCurent = this->m_listAdiacenta[nod][i];
            //verificam daca vecinul curent nu a fost inca vizitat
            if(arrivalTime[vecinCurent] == -1){
                //aplicam tarjan pe nodul curent
                tarjan(vecinCurent);
                //la iesire incercam sa minimizam valoarea low link a nodului curent, daca vecinul la care suntem a facut in timpul tarjan-ului una mai mica
                if(lowLinkValue[vecinCurent] < lowLinkValue[nod]){
                    lowLinkValue[nod] = lowLinkValue[vecinCurent];
                }
            }else{  //daca vecinul a fost deja vizitat
                //verificam daca vizitarea s-a produs in cadrul componentei tare conexe curente
                if(isInStiva[vecinCurent] == 1){
                    //incercam sa minimizam valoarea low link a nodului curent, in cazul in care vecinul curent ajunge la un nod mai indepartat decat valoarea noastra curenta
                    if(lowLinkValue[vecinCurent] < lowLinkValue[nod]){
                        lowLinkValue[nod] = lowLinkValue[vecinCurent];
                    }
                }
            }
        }
        //verificam daca nodul curent inchide o componenta tare conexa
        if(arrivalTime[nod] == lowLinkValue[nod]){
            //trebuie sa mutam componenta tare conexa curenta din stiva in vectorul cu toate componentele tare conexe din graf
            vector<int> aux;
            int nodAux;
            do{
                nodAux = StivaComponentaTareConexaCurenta.top();
                aux.push_back(nodAux);
                StivaComponentaTareConexaCurenta.pop();
                isInStiva[nodAux] = 0;
            }while(nodAux != nod);
            ComponenteTareConexe.push_back(aux);
        }
    }

    void afisComponenteTareConexe(){
        ofstream g("../ctc.out");
        g<<ComponenteTareConexe.size()<<"\n";
        for(int i=0; i<ComponenteTareConexe.size(); i++){
            for(int j=0; j<ComponenteTareConexe[i].size(); j++){
                g<<ComponenteTareConexe[i][j]<<" ";
            }
            g<<"\n";
        }
    }

    void numaraComponenteTareConexe(){
        isInStiva.assign(this->m_nrNoduri + 1, 0);
        arrivalTime.assign(this->m_nrNoduri + 1, -1);
        lowLinkValue.resize(this->m_nrNoduri + 1);
        for(int i=1; i<=this->m_nrNoduri; i++){
            if(arrivalTime[i] == -1){
                tarjan(i);
            }
        }
        afisComponenteTareConexe();
    }
};

int main() {
    ofstream out("../biconex.out");

    Graf g;

    g.citire();

    g.numaraComponenteTareConexe();
    return 0;
}