Cod sursa(job #1999324)

Utilizator BogdanisarBurcea Bogdan Madalin Bogdanisar Data 10 iulie 2017 21:42:49
Problema Componente tare conexe Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 3.46 kb
#include <iostream>
#include <fstream>
#include <stack>
#include <vector>

using namespace std;
ifstream in("ctc.in");
ofstream out("ctc.out");

// algoritmul Kosaraju
// O(N+M)

#define ll long long
#define pb push_back
const int inf = 1e9 + 5;
const int NMax = 1e5 + 5;

int N,M,nrComp;
bool inStack[NMax],vis[NMax];
stack<int> st;
vector<int> v[NMax],rev[NMax],comp[NMax];
// nrComp - numarul de componente care s-au gasit pana la un moment dat;
// inStack[i] = true daca nodul i a fost bagat in stiva
//              ca rezultat al primei parcurgeri dfs (build);
// vis[i] = true daca nodul i a fost parcurs in cea de-a doua
//          parcurgere dfs si deci a fost gasita componenta conexa din care el face parte;
// st - stiva generata prin functia build();
//      aceasta are proprietatea ca, fiind date doua noduri u si v,
//      daca exista drum de la u la v, dar nu exista drum de la v la u,
//      atunci nodul v se afla obligatoriu mai jos in stiva decat nodul u;
//      daca exista ambele drumuri, cele doua au o ordine aleatorie;
// v - liste de adiacenta pentru graful dat;
// rev - liste de adiacenta pentru graful transpus;
// comp[i] - contine nodurile din a i-a componenta conexa;

void build(int);
void dfs(int);

int main() {
    in>>N>>M;
    while (M--) {
        int x,y;
        in>>x>>y;

        v[x].pb(y);
        rev[y].pb(x);
    }

    // se construieste stiva st care va contine toate nodurile exact o data
    // si va avea proprietatea enuntata mai sus
    for (int i=1;i <= N;++i) {
        if (inStack[i]) {
            continue;
        }

        build(i);
    }

    // se realizeaza dfs-uri pe arcele din graful transpuns in ordine inversa
    // a nodurilor din stiva si se formeaza componentele tare conexe;
    // faptul ca algoritmul este corect se poate arata prin:
    // - urmatorul loop-invariant:
    //   s-a gasit componenta conexa pentru toate nodurile vizitate anterior
    //   iar toate nodurile scoase deja din stiva au fost vizitate;
    // - urmatoarele observatii:
    // * daca exista back arch de la nodul i din dfs la nodul j,
    //   atunci exista obligatoriu drum de la i la j;
    // * daca se merge prin back-arches de la nodul i la alte noduri,
    //   va exista obligatoriu drum de la i la aceste noduri
    //   (caci altfel i n-ar fi deasupra lor in stiva)
    // * daca un nod k si nodul i se afla in aceeasi componenta,
    //   dar nu exista back-arch de la i la k, atunci obligatoriu
    //   va exista un drum de back-arches de la i la k, caz in care
    //   se va ajnge la k prin dfs si exista drum in graful dat de la i la k
    //   (conform observatiei anterioare)

    while (st.size()) {
        int node = st.top();
        st.pop();

        if (vis[node]) {
            continue;
        }

        ++nrComp;
        dfs(node);
    }

    out<<nrComp<<'\n';
    for (int i=1;i <= nrComp;++i) {
        for (int node : comp[i]) {
            out<<node<<' ';
        }
        out<<'\n';
    }

    in.close();
    out.close();
    return 0;
}

void build(int node) {
    inStack[node] = true;

    for (int nxt : v[node]) {
        if (inStack[nxt]) {
            continue;
        }

        build(nxt);
    }

    st.push(node);
}

void dfs(int node) {
    vis[node] = true;
    comp[nrComp].pb(node);

    for (int nxt : rev[node]) {
        if (vis[nxt]) {
            continue;
        }

        dfs(nxt);
    }
}