Cod sursa(job #1847503)

Utilizator mariusmagureanmagurean marius mariusmagurean Data 14 ianuarie 2017 17:59:49
Problema Componente biconexe Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 5.43 kb
/*
se cer toate componentele biconexe dintr un graf neorientat conex
o componenta este biconexa daca nu are vreun punct de articulatie
un punct de articulatie este un nod care daca ar fi sters invalideaza proprietatea de conexitate

Un punct i este de articulatie daca intr o parcurgere dfs, el reprezinta radacina arborelui partial generat si are cel putin
2 descendenti directi sau daca nu reprezinta radacina si exista cel putin un fiu j care sa nu aiba legatura printr un lant,
altul decat cel generat de dfs, cu un nod situat inaintea lui i in ordinea generata de parcurgeres dfs (pe muchii de intoarcere)

Pornind de la aceasta caracterizare a unui punct de articulatie, vom determina punctele astfel:

- vectorul ord[i] retine numarul de ordine al lui i in parcurgerea dfs. De ex, daca parcurgerea incepe de la 1, ord[1]=1
- vectorul lowLink[i] va retine numarul de ordine al primului nod din parcurgerea dfs ce poate fi atins din i pe un alt drum
decat cel generat de parcurgerea dfs
- cu acesti doi vectori, i va fi punct de articulatie daca ord[1]=1 si are cel putin doi descendenti directi
sau daca ord[i]!=1 si are un descendent direct j, cu lowLink[j]>=ord[i]

pentru a calcula ord[i] se va folosi o variabila globala nrOrd care va retine numarul de ordine al nodului curent din dfs
pentru a calcula lowLink[i] se va folosi formula
    lowLink[i]=min(ord[i], min(lowLink(j), j fiu al lui i), min(ord[j], unde [i,j] este muchie de intoarcere))

graful va fi memorat ci listele de adiacenta retinute de o matrice, unde coloana 0 va retine pentru fiecare linie, numarul de fii

pentru a identifica componentele biconexe, vom folosi o stiva care retine muchiile grafului(indiferent daca fac parte din dfs
sau sunt muchii de intoarcere) in ordinea parcurgerii dfs. Cand identificam un punct de articulatie,
eliminam din stiva toate muchiile din componenta biconexa respectiva

Variabila cate retine numarul de componente biconexe, iar varf retine indicele varfului stivi

v[i]=1, daca muchia de indice i din stiva contine punctul de articulatie

Consider pentru simplitate nodul 1 ca fiind de start in dfs si ii retin numarul de fii in nrFii

*/
#include <fstream>
#include<vector>
#include<algorithm>

//#include<stack>
#define dim 200005
using namespace std;

struct muchie
{
    int fiu, tata;
};

muchie S[dim];
vector<int>a[dim];
vector<vector <int> >bi;
int ord[dim],lowLink[dim],cate,nrOrd,varf;
int n,m;

void citire()
{
    int i,j,k,x,y;
    ifstream fin("biconex.in");
    fin>>n>>m;
    for(k=1;k<=m;k++)
    {
        fin>>x>>y;
        a[x].push_back(y);
        a[y].push_back(x);
    }
    fin.close();
}

void dfs(int nodCurr, int nodTata)
{
    //nodCurr este nodul curent, iar nodTata este nodul lui parinte
    int i,nod,j,x,y;
    muchie h;
    //cand se ajunge aici crestem numarul de ordine din dfs si il atribuim si lui ord si lui lowLink
    nrOrd++;
    ord[nodCurr]=lowLink[nodCurr]=nrOrd;
    //i este variabila de parcurgere a listei unui nod
    //nod este nodul adiacent lui nodCurr
    //parcurg lista de adiacenta a nodului nodCurr
    for(i=0;i<a[nodCurr].size();i++)
    {
        nod=a[nodCurr][i];
        //daca`nodul este chiar parintele nu ne intereseaza
        if(nod==nodTata)
            continue;
        //daca nod nu a mai fost vizitat
        if(ord[nod]==-1)
        {
            //introduc in S muchia (nod,nodCurr)
            h.tata=nodCurr;
            h.fiu=nod;
            varf++;S[varf]=h;
            //reapelez functia pentru nod si nodCurr care va deveni nodTata
            dfs(nod,nodCurr);
            //la derecursivitate
            //calculez minimul dintre lowLink de extremitatile muchiei nodCurr, nod
            lowLink[nodCurr]=min(lowLink[nodCurr],lowLink[nod]);
            //daca nodCurr este punct de articulatie, am gasit o componenta biconexa
            //formata din toate muchiile stivei pana la intalnirea muchiei [nodCurr,nod]
            if(lowLink[nod]>=ord[nodCurr])
            {
                cate++;
                //copii in matricea bi, componenta conexa din stiva
                //vectorul aux retine acea componenta luata din S
                vector<int>aux;
                do
                {
                   x=S[varf].fiu;
                   y=S[varf].tata;
                   varf--;
                   aux.push_back(x);
                   aux.push_back(y);
                }
                while(y!=nodCurr || x!=nod);
                bi.push_back(aux);
            }
        }
        else
        {
            //in acez caz nodCurr a mai fost vizitat, verific daca este o muchie de intoarcere
            if(nodCurr!=nodTata)
                lowLink[nodCurr]=min(lowLink[nodCurr],ord[nod]);
        }

    }
}

int main()
{
    ofstream fout("biconex.out");
    citire();
    int i,j;
    for(i=1;i<=n;i++)
        ord[i]=lowLink[i]=-1;
    //initializez stiva cu noduk de pornire, el nu are tata, consider -1
    S[0].fiu=1;
    S[0].tata=-1;
    dfs(1,0);
    fout<<cate<<"\n";
    //afisez fiecare linie a lui bi
    //in fiecare linie unele noduri apar de mai multe ori si sunt in ordine inversa
    for(i=0;i<bi.size();i++)
    {
        //elimim duplicatele
        sort(bi[i].begin(), bi[i].end());
        bi[i].erase(unique(bi[i].begin(), bi[i].end()), bi[i].end());
        for(j=0;j<bi[i].size();j++)
            fout<<bi[i][j]<<" ";
        fout<<"\n";
    }
    return 0;
}