Cod sursa(job #2793801)

Utilizator XeinIonel-Alexandru Culea Xein Data 4 noiembrie 2021 01:53:52
Problema Componente tare conexe Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.5 kb
#include <fstream>
#include <vector>
#include <algorithm>
#include <cstring> 
 
class Graf
{
private:
    static constexpr int NMAX = 100009;
    const int N, M;
    std::vector<int> Adiacenta[NMAX];  // liste de adiacenta
 
public:
    Graf(int, int);
    void AdMuchie(int, int);
    void Bfs(int, int*);
    int Dfs();
    void Biconex(std::vector<std::vector<int>>&);
    void CompTareConexe(std::vector<int>*, std::vector<std::vector<int>>&, int&);

    static constexpr int getNMAX() { return Graf::NMAX; }

private:
    void Dfs_fHelper(int, bool*);
    void Biconex_fHelper(int, int, std::pair<int, int>*, int&, int*, int*, std::vector<std::vector<int>>&);
    void CompTareConexe_Dfs(int, bool*, int*, int&);
    void CompTareConexe_t_Dfs(int, bool*, std::vector<int>*, std::vector<std::vector<int>>&, int);
};
 
Graf::Graf(int n, int m)
    : N(n), M(m)
{
}
 
void Graf::AdMuchie(int ini, int fin)
{
    Adiacenta[ini].push_back(fin);
}

void Graf::Bfs(int S, int* nrArce)
{
    int coada[NMAX], st = 0, dr = 0;
 
    for (int i = 1; i <= N; ++i)
        nrArce[i] = -1;
    nrArce[S] = 0;
    coada[st] = S;
    while (st <= dr)
    {
        int curent = coada[st++];
        for (auto it = Adiacenta[curent].begin(); it != Adiacenta[curent].end(); ++it)
            if(nrArce[*it] == -1)
            {
                coada[++dr] = *it;
                nrArce[*it] = nrArce[curent] + 1;
            }
    }
}

int Graf::Dfs()
{
    bool vizitat[NMAX];
    int nrComp = 0;

    memset(vizitat, 0, NMAX * sizeof(bool));
    for (int i = 1; i <= N; ++i)
        if (!vizitat[i])
        {
            ++nrComp;
            Dfs_fHelper(i, vizitat);
        }

    return nrComp;
}

void Graf::Dfs_fHelper(int curent, bool* vizitat)
{
    vizitat[curent] = true;
    for (auto it = Adiacenta[curent].begin(); it != Adiacenta[curent].end(); ++it)
        if (!vizitat[*it])
            Dfs_fHelper(*it, vizitat);
}

void Graf::Biconex(std::vector<std::vector<int>>& compBic)
{
    std::pair<int, int> Stiva[NMAX * 2];
    int stVf = 0;
    int nivelInArbDFS[NMAX];  // folosit si ca vizitat[]
    int nivelMinVecini[NMAX];

    nivelInArbDFS[0] = 0;
    Biconex_fHelper(1, 0, Stiva, stVf, nivelInArbDFS, nivelMinVecini, compBic);
}

void Graf::Biconex_fHelper(int nod, int parinte, std::pair<int, int>* Stiva, int& stVf, int* nivelInArbDFS, int* nivelMinVecini, std::vector<std::vector<int>>& compBic)
{
    nivelInArbDFS[nod] = nivelInArbDFS[parinte] + 1;
    nivelMinVecini[nod] = NMAX;
    for (int& vecin : Adiacenta[nod])
    {
        if (nivelInArbDFS[vecin])  // daca e vizitat
        {
            if (nivelMinVecini[nod] > nivelInArbDFS[vecin] && vecin != parinte)
                nivelMinVecini[nod] = nivelInArbDFS[vecin];
        }
        else
        {
            Stiva[++stVf] = {nod, vecin};
            Biconex_fHelper(vecin, nod, Stiva, stVf, nivelInArbDFS, nivelMinVecini, compBic);

            if (nivelMinVecini[nod] > nivelMinVecini[vecin])
                nivelMinVecini[nod] = nivelMinVecini[vecin];
            
            if (nivelMinVecini[vecin] >= nivelInArbDFS[nod])
            {
                compBic.push_back({});
                while (Stiva[stVf].first != nod)
                    compBic.back().push_back(Stiva[stVf--].second);
                compBic.back().push_back(Stiva[stVf].second);  // muchia din 'nod', intreaga
                compBic.back().push_back(Stiva[stVf].first);   //
                --stVf;
            }
        }
    }
}

void Graf::CompTareConexe(std::vector<int>* t_Adiacenta, std::vector<std::vector<int>>& compTC, int& nrComp)
{
    int stivaTopo[NMAX], stVf = 0;    // stivaTopo - stiva de noduri in care nodurile sunt inserate in ordinea topologica inversata
    bool vizitat[NMAX];

    memset(vizitat, 0, (N + 1) * sizeof(bool));
    for (int nod = 1; nod <= N; ++nod)
        if (!vizitat[nod])
            CompTareConexe_Dfs(nod, vizitat, stivaTopo, stVf);

    compTC.resize(N);
    nrComp = 0;
    memset(vizitat, 0, (N + 1) * sizeof(bool));
    while (stVf)
    {
        if (!vizitat[stivaTopo[stVf]])
            CompTareConexe_t_Dfs(stivaTopo[stVf], vizitat, t_Adiacenta, compTC, nrComp++);
        --stVf;
    }
}

void Graf::CompTareConexe_Dfs(int nod, bool* vizitat, int* stivaTopo, int& stVf)
{
    vizitat[nod] = true;
    for (auto& vecin : Adiacenta[nod])
        if (!vizitat[vecin])
            CompTareConexe_Dfs(vecin, vizitat, stivaTopo, stVf);
    stivaTopo[++stVf] = nod; 
}

void Graf::CompTareConexe_t_Dfs(int nod, bool* vizitat, std::vector<int>* t_Adiacenta, std::vector<std::vector<int>>& compTC, int nrComp)
{
    vizitat[nod] = true;
    for (auto& vecin : t_Adiacenta[nod])
        if (!vizitat[vecin])
            CompTareConexe_t_Dfs(vecin, vizitat, t_Adiacenta, compTC, nrComp);
    compTC[nrComp].push_back(nod);
}


int main()
{   
    std::ifstream f("ctc.in");
    std::ofstream g("ctc.out");
    int N, M;
    std::vector<int> t_Adiacenta[Graf::getNMAX()];  // Transpus

    f >> N >> M;
    Graf graf(N, M);
    for (int x, y, i = 0; i < M; ++i)
    {
        f >> x >> y;
        graf.AdMuchie(x, y);
        t_Adiacenta[y].push_back(x);
    }

    std::vector<std::vector<int>> compTC;
    int nrComp;
    graf.CompTareConexe(t_Adiacenta, compTC, nrComp);
 
    g << nrComp << '\n';
    for (auto& comp : compTC)
    {
        for (int& nod : comp)
            g << nod << ' ';
        g << '\n';
    }
    return 0;
}