Cod sursa(job #2928790)

Utilizator radubuzas08Buzas Radu radubuzas08 Data 23 octombrie 2022 21:28:44
Problema Componente tare conexe Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.13 kb
// CTC - TARJAN
// Created by Radu Buzas on 22.10.2022.
//

/*
 * Complexitate timp O(n+m)
 *
 * Algoritmul implmentat este algoritmul lui Tarjan pentru componente tari conexe. Asignez fiecarui nod parcurs prin DFS un id si un low.
 * ID-ul simbolizeaza de fapt la al catelea nod sunt, iar low este id-ul minim al unui nod din subgraful tare conex. Low este actualizat
 * la fiecare pas al DFS-ului.
 *
 * Pornesc de la un nod aleator, verific vecinii, daca sunt nevizitati ii vizitez si ulterior verific daca label-ul(low) lor este mai mic
 * decat cel al nodului curent, practic fac un minim dintre low[k], unde k este nodul curent, si low[i], unde i poate fi orice vecin al
 * nodului curent.
 * Cand vizitez un nod il introduc pe stiva.
 * Daca nodul vecin al nodul curent este deja vizitat SI este pe stiva, atunci calculez minimul dintre low[k] si low[i], stocand rezultatul
 * in low[k].
 * Dupa verificarea vecinilor verific daca label-ul(low) corespunde cu id, daca corespund atunci scot de pe stiva elementele pana dau de
 * nodul curent(si el este scos de pe stiva). Nodurile scoase reprezinta nodurile ce compun CTC.
 *
 * Repet procesul pana cand gasesc toate CTC
 *
 * Afisez nodurile ce alcatuiesc toate CTC
 * Pentru infoarena am sortat crescator vectorul ce contine nodurile din CTC. In cel mai rau caz, complexitatea ar deveni O(n*log(n)),
 * daca tot graful ar fi o componenta tare conexa. Fiind doar o chestiune de afisare am considerat ca nu ar fi necesara mentionarea sa
 * in ceea ce priveste complexitatea de timp mentionata in prima linie a comentariului
 * */

#include <fstream>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;

#define min(a, b)  ( (a < b) ? a : b)       //  macro-ul este putin mai rapid

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

int incide = 1;                             //  ID-ul folosit pentru detectarea CTC

void dfs(vector<vector<int>> & graph, vector<int> & id, vector<int> & low, stack<int> & s, vector<bool> &inStack, vector<vector<int>> & sol, int k){
    inStack[k] = true;
    low[k] = id[k] = incide++;              //  id-ul reprezinta la al catelea nod in parcurgere am ajuns
    s.push(k);                          //  adaug pe stiva nodul la care sunt
    for (auto x : graph[k]){            //  parcurg vecinii lui k
        if(!id[x])                          //  daca id-ul este 0, atunci nodul este nevizitat
            dfs(graph, id, low, s, inStack, sol, x), low[k] = min(low[k], low[x]);  //  DFS + minimul dintre nodul curent(k) si vecinul sau(x) cand vine vorba de label
        else if(inStack[x])                 //  daca nodul vecin(x) este vizitat si se afla pe stiva, atunci nodul curent ia valoarea minima dintre label-ul curent si label-ul vecinului sau(x)
            low[k] = min(low[k], low[x]);
    }
    if(id[k] == low[k]){                    //  daca label-ul (id-ul cel mai mic din componenta conexa) corespunde id-ului, atunci am descoperit componenta tare conexa
        vector<int> tmp;
        while(s.top() != k)                 //  golesc toate elementele asociate CTC-ului din stiva
            inStack[s.top()] = 0, tmp.push_back(s.top()) , s.pop();
        inStack[s.top()] = 0, tmp.push_back(s.top()), s.pop();      //  construiesc un vector temporar care contine nodurile din CTC
        sol.push_back(tmp);                 //  Adaug vectorul obtinut la solutie
        tmp.clear();
    }
}

int main(){
    int n, m, x, y;
    in >> n >> m;
    vector<vector<int>> graph(n +1), sol;
    vector<int> id(n+1, 0), low(n+1, 0);
    vector<bool> boolV(n+1, 0);
    stack<int> s;
    while(m--){
        in >> x >> y;
        graph[x].push_back(y);          //  graf orientat
    }
    in.close();

    for(int i = 1; i <= n; i++)         //  parcurg toate nodurile
        if(!id[i])                      //  apelez DFS pt nodurile nevizitate
            dfs(graph, id, low,s, boolV, sol, i);

    out << sol.size() << '\n';
    for (auto x : sol) {
        sort(x.begin(), x.end());       //  sortez pentru ca nodurile din CTC sa fie prezentate in ordine crescatoare
        for (auto y: x) {
            out << y << ' ';
        }
        out << '\n';
    }

    out.close();
    return 0;
}