Cod sursa(job #2925770)

Utilizator mirceaspPetcu Mircea mirceasp Data 16 octombrie 2022 00:00:29
Problema Componente tare conexe Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.66 kb
//Complexitate: O(n+m) din cauza dfs-ului
#pragma GCC optimize("O3")
#pragma GCC optimize("Ofast")
#pragma GCC optimize ("unroll-loops")
#include <bits/stdc++.h>
#include <fstream>
using namespace std;
std::ifstream f("ctc.in");
ofstream g("ctc.out");
void dfs(int &start, vector<bool> & vizitat,vector<vector<int>> &lista,vector<bool> &tarjan, vector<int> &index,vector<int> & low,int &nr,stack<int> &stack,vector<vector<int>> &sol,int &nrCTC)
{
    stack.push(start);
    vizitat[start] = true;
    tarjan[start] = true;
    index[start] = low[start] = nr;
    nr++;
    //pun nodul curent pe stiva, il nodez in tarjan ca fiind pe stiva, in vectorul vizitat ca fiind vizitat, iar index este egal cu low care primeste nr(al catelea element
    //este parcurs pe dfs) deoarece deocamdata cel mai adanc nod in care ne putem duce este el insusi
    for(int i = 0;i<lista[start].size();i++)
    {if(vizitat[lista[start][i]] == false)
            dfs(lista[start][i], vizitat, lista,tarjan,index,low,nr,stack,sol,nrCTC);
        //vecinii nodului curent ii pun pe stiva programului
            if(tarjan[lista[start][i]] == true)
                low[start] = min(low[start],low[lista[start][i]]);}
            //cel mai adanc punct al nodului curent poate fi unul dintre vecinii lui sau un nod conectat la unul dintre vecinii lui s.a.

    if(index[start] == low[start])
        //daca unui nod i-au fost parcursi toti vecinii inseamna ca nu are unde sa se duca mai departe, si daca cel mai indepartat punct in care poate sa ajunga
        //este chiar el insusi inseamna ca, parcurcand stiva declarata pana la el avem o ctc
    {
        vector<int>v;
        int elementDinStiva = stack.top();
        v.push_back(elementDinStiva);
        while (elementDinStiva != start)
        {
            tarjan[elementDinStiva] = false;
            //il marcam ca nu mai fiind pe stiva
            low[elementDinStiva] = index[start];
            //iar cel mai indepartat nod primeste indexul nodului curent(start) deoare face parte din aceeasi ctc
            stack.pop();
            elementDinStiva = stack.top();
            v.push_back(elementDinStiva);
        }
        tarjan[start] = false;
        stack.pop();
        sol.push_back(v);
        nrCTC++;
        //punem ctc in vectorul de solutii si incrementam numarul de solutii

    }
}
int main(){
    int n,m,i,a,b;
    vector<vector<int>> lista;
    f>>n>>m;
    for(i = 0;i<=n;i++)
        lista.push_back({});
    while (f>>a>>b)
    {
        lista[a].push_back(b);
    }
    stack<int> stack;
    //stiva pentru pastrarea nodurilor din elementele conexe
    vector<bool> vizitat(n+1,false);
    //vector de vizitat pentru nodurile grafurior
    vector<bool> stivaTarjan(n+1,false);
    //daca un nod se afla pe stiva declarata anterior avem true, altfel avem false
    vector<int> index(n+1,0);
    //vector pentru a pastra al catelea nod este parcurs prin dfs-ul nostru
    vector<int> low(n+1,0);
    //vector pentru fiecare nod pentru a afla cat de adancime se poate duce un nod
    int nr = 1,nrCTC = 0;
    //nr este pentru a i oferii un index fiecarui nod parcurs cu dfs, iar nrCTC este numarul de componente conexe
    vector<vector<int>> sol;
    //sol este vectorul de solutii
    for(int i = 1;i<=n;i++)
        if(vizitat[i] == false)
            dfs(i,vizitat,lista,stivaTarjan,index,low,nr,stack,sol,nrCTC);
    //cat timp pot incepe de undeva apelez dfs-ul pe nodul respectiv

    g<<nrCTC<<endl;
    for(auto j: sol) {
        for (int k = 0; k < j.size(); k++)
            g << j[k] << ' ';
        g << endl;
    }
    f.close();g.close();
    //afisez solutia
    return 0;


}