Cod sursa(job #3272121)

Utilizator AndreeaHzmAndreea Huzum AndreeaHzm Data 28 ianuarie 2025 15:07:38
Problema Componente tare conexe Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.87 kb
#include <fstream>
#include <vector>
#include <algorithm>

#define maxi 100001

using namespace std;

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

class Graf {
    int nrNoduri, nrMuchii;         // Numarul de noduri si muchii
    int x, y;                      // Nodurile unei muchii (x -> y)
    vector<int> *adiacenta;        // Lista de adiacenta pentru graf
    vector<int> *adiacenta2;       // Lista de adiacenta pentru graful transpus
    int vizitat[maxi] = {0};       // Vector pentru marcarea nodurilor vizitate

public:
    Graf();
    ~Graf();

    void citireComponenteTareConexe(); // Citirea grafului orientat
    void DF1(int nodPlecare, vector<int> &succesor, vector<int> &v, int &index); // DFS pe graful initial
    void DF2(int nodPlecare, vector<int> &predecesor, int &nrComponenteTareConexe); // DFS pe graful transpus
    void afisareComponenteTareConexe(); // Determinarea si afisarea componentelor tare conexe
};

Graf::Graf() {
    nrNoduri = nrMuchii = x = y = 0;
    adiacenta = new vector<int>[maxi];   // Alocare memorie pentru lista de adiacenta
    adiacenta2 = new vector<int>[maxi]; // Alocare memorie pentru lista de adiacenta transpus
}

Graf::~Graf() {
    delete[] adiacenta;  // Eliberare memorie pentru lista de adiacenta
    delete[] adiacenta2; // Eliberare memorie pentru lista de adiacenta transpus
}

// Citirea grafului orientat si construirea grafului transpus
void Graf::citireComponenteTareConexe() {
    fin >> nrNoduri >> nrMuchii; // Citim numarul de noduri si muchii
    for (int i = 1; i <= nrMuchii; i++) {
        fin >> x >> y;               // Citim fiecare muchie (x -> y)
        adiacenta[x].push_back(y);   // Adaugam nodul y ca succesor al lui x
        adiacenta2[y].push_back(x);  // Adaugam nodul x ca succesor al lui y in graful transpus
    }
}

// DFS pe graful initial pentru a construi ordinea nodurilor
void Graf::DF1(int nodPlecare, vector<int> &succesor, vector<int> &v, int &index) {
    succesor[nodPlecare] = 1; // Marcam nodul ca vizitat
    for (auto i : adiacenta[nodPlecare]) { // Parcurgem toti vecinii nodului curent
        if (!succesor[i]) {
            DF1(i, succesor, v, index); // Apel recursiv pentru vecinul curent
        }
    }
    v[++index] = nodPlecare; // Adaugam nodul in ordinea finala (postordine DFS)
}

// DFS pe graful transpus pentru a determina componentele tare conexe
void Graf::DF2(int nodPlecare, vector<int> &predecesor, int &nrComponenteTareConexe) {
    predecesor[nodPlecare] = nrComponenteTareConexe; // Marcam componenta nodului curent
    for (auto i : adiacenta2[nodPlecare]) { // Parcurgem toti vecinii in graful transpus
        if (!predecesor[i]) {
            DF2(i, predecesor, nrComponenteTareConexe); // Apel recursiv pentru vecinul curent
        }
    }
}

// Determinarea si afisarea componentelor tare conexe folosind algoritmul Kosaraju
void Graf::afisareComponenteTareConexe() {
    vector<int> succesor(nrNoduri + 1, 0);   // Vector pentru a marca vizitarea nodurilor in primul DFS
    vector<int> predecesor(nrNoduri + 1, 0); // Vector pentru a marca componentele nodurilor in al doilea DFS
    vector<int> v(nrNoduri + 1, 0);          // Vector pentru a stoca ordinea nodurilor din primul DFS
    pair<int, int> p[nrNoduri + 1];          // Perechi pentru sortarea nodurilor dupa componente
    int nrComponenteTareConexe = 1, index = 0;

    // Primul DFS pe graful initial pentru a construi ordinea nodurilor
    for (int i = 1; i <= nrNoduri; i++) {
        if (succesor[i] == 0) {
            DF1(i, succesor, v, index);
        }
    }

    // Al doilea DFS pe graful transpus pentru a determina componentele tare conexe
    for (int i = nrNoduri; i >= 1; i--) {
        if (predecesor[v[i]] == 0) {
            DF2(v[i], predecesor, nrComponenteTareConexe);
            nrComponenteTareConexe++;
        }
    }

    // Afisam numarul de componente tare conexe
    fout << nrComponenteTareConexe - 1 << '\n';

    // Sortam nodurile in functie de componente
    for (int i = 1; i <= nrNoduri; i++) {
        p[i].first = predecesor[i]; // Componenta nodului curent
        p[i].second = i;           // Valoarea nodului curent
    }
    sort(p + 1, p + nrNoduri + 1); // Sortam nodurile dupa componenta lor

    // Afisam nodurile din fiecare componenta tare conexa
    for (int i = 1; i <= nrNoduri; i++) {
        if (p[i].first != p[i + 1].first) {
            fout << p[i].second << '\n';
        } else {
            fout << p[i].second << " ";
        }
    }
}

int main() {
    Graf g1; // Cream un obiect al clasei Graf
    g1.citireComponenteTareConexe(); // Citim graful orientat si graful transpus
    g1.afisareComponenteTareConexe(); // Determinam si afisam componentele tare conexe

    fin.close(); // Inchidem fisierul de intrare
    fout.close(); // Inchidem fisierul de iesire

    return 0;
}