Cod sursa(job #2928704)

Utilizator Nicolae11Mihaila Nicolae Nicolae11 Data 23 octombrie 2022 18:16:19
Problema Componente tare conexe Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.45 kb
/* Algoritmul acesta este o implementare a algoritmului lui Tarjan de gasire a numarului de componente tare conexe si a acestora. Mai intai voi explica
ce trebuie sa stim inainte de a evalua programul, iar apoi il voi explica.
Valoare low link = nodul cu indexul cel mai mic in care poate ajunge un nod prin parcurgeri
Algoritmul functioneaza astfel:
    Initial, toate nodurile sunt nevizitate (nu au asociat un ID, iar valoarea lor low link este insasi indexul lor (adica am presupune ca sunt noduri
izolate). Parcurgem vectorul de ID-uri, iar acolo unde gasim un nod nevizitat, pornim algoritmul lui Tarjan (adica e posibil sa avem o noua componenta
tare conexa). Trecem prin lista de adiacenta a nodului curent si exploram toti vecinii (facem un DFS). Daca nodul pe care l-am vizitat pe urma ramane
pe stiva, inseamna ca acesta nu face parte din alta componenta conexa, deci ii modificam valoarea low link corespunzator. Daca gasim un nod pentru care
valoarea low link este egala cu indicele sau, inseamna ca acesta formeaza o componenta tare conexa (fie el nod izolat sau o componenta mai mare),
deci urmeaza sa extragem componenta conexa prin golirea stivei de elementele care sunt deasupra, pana la cel care are valoarea low link egala cu
ID-ul sau. Aceasta este una dintre componentele conexe. Stiva nu ramane neaparat vida. La final, afisam numarul de componente conexe si componentele
in sine.
Complexitate:
Timp: O(n+m)
Memorie: O(n*m) ///din cauza lui liste si afisare, pe care le-as putea reduce la O(n+m) daca le-as face vector<vector<int>>
liste = listele de adiacenta
afisare = un vector in care imi tin componentele tare conexe
k = numarul de componente conexe
low_link = valorile low link ale nodurilor
pe_stiva = ne spune daca nodul e pe stiva sau nu
iduri = ne spune daca nodului i-a fost atribuit un ID
*/
#include <iostream>
#include <fstream>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
ifstream f("ctc.in");
ofstream g("ctc.out");
int n,m,k,low_link[100005],pe_stiva[100005],viz[100005],iduri[100005],id;
stack<int> stiva;
vector<int> liste[100005],afisare[100005];

void Tarjan(int curent)
{
    stiva.push(curent);
    pe_stiva[curent]=1;
    low_link[curent]=iduri[curent]=id++;
    for(auto j : liste[curent])  ///cred ca aici e problema. Modul in care marcam ca vizitati ne face sa nu putem explora cum trebuie?
    {
        if(iduri[j]==0) ///aici am facut modificarea care schimba componentele conexe. Asa ne da prea multe, dar le include pe alea bune
            Tarjan(j);
        if(pe_stiva[j]==1)
            low_link[curent]=min(low_link[curent],low_link[j]);
    }
    if(low_link[curent]==iduri[curent])
    {
        k++;
        int aux=stiva.top();
        while(aux!=curent)
        {
            pe_stiva[aux]=0;
            low_link[aux]=curent;
            afisare[k].push_back(aux);
            stiva.pop();
            aux=stiva.top();
        }
        pe_stiva[curent]=0;
        afisare[k].push_back(aux);
        stiva.pop();
    }
    return;
}
int main()
{   f>>n>>m;
    int st,dr;
    for(int i=1;i<=m;i++)
    {   f>>st>>dr;
        liste[st].push_back(dr);
    }
    id=1;
    for(int i=1;i<=n;i++)
        if(iduri[i]==0)   ///aici s-ar putea sa fie o problema.
            Tarjan(i);
    g<<k<<'\n';
    for(int i=1;i<=k;i++)
    {   for(auto j : afisare[i])
            g<<j<<' ';
        g<<'\n';
    }
    f.close();
    g.close();
    return 0;
}