Cod sursa(job #2798127)

Utilizator MadalinaKopaczMadalina Kopacz MadalinaKopacz Data 10 noiembrie 2021 22:23:51
Problema Componente biconexe Scor 40
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 14.19 kb
#include <bits/stdc++.h>
using namespace std;


///Clasa pentru reprezentare de grafuri
class Graf
{
private:
    int nrNoduri;
    int nrMuchii;
    vector<vector<int>> lisAdiacenta;

    vector<int> BFS(const int nodStart);
    void DFS(const int nodStart, vector<bool> &vizitat, stack<int> &stiva);
    void ctcDFS(int x, vector<int> &disc, vector<int> &low, stack<int> &stiva, vector<bool> &gasitStiva, vector<vector<int>> &rez);
    void critConDFS(int x, vector<bool> &viz, vector<int> &disc, vector<int> &low, vector<int> &tata, ostream &out);
    void biconexeDFS(int x, vector<int> &disc, vector<int> &low, stack<pair<int, int>> &comp, vector<int> &tata, vector<set<int>> &rez);
public:
    Graf(const int nrNoduriDat, const int nrMuchiiDat);
    Graf(const int nrNoduriDat, const int nrMuchiiDat, const vector<vector<int>> &listaData);
    Graf(const Graf &grafDat);
    ~Graf();

    int getNrNoduri();
    int getNrMuchii();

    Graf& operator= (const Graf &grafDat);
    friend std::ostream& operator<<(std::ostream &out, const Graf &grafDat);

    void citireOrientat(istream &in);
    void citireNeorientat(istream &in);


    void afisareDistanteBFS(const int nodStart, ostream &out);
    int nrCompConexe();
    void sortareTopologica(ostream &out);
    bool Havel_Hakimi(vector<int> &grade);
    static void existaGraf(vector<int> &grade, ostream &out);
    void CTC(ostream &out);
    void CriticalConnections(ostream &out);
    void Biconex(ostream &out);

};

///CONSTRUCTORI
Graf :: Graf(const int nrNoduriDat, const int nrMuchiiDat)  //constructor parametrizat - nu avem lista de adiacenta
{
    nrNoduri = nrNoduriDat;
    nrMuchii = nrMuchiiDat;

    vector<int> aux(1,-1);       //initializam prima pozitie cu -1 pentru ca indexarea e de la 1
    for(int i = 0; i <= nrNoduri+1; ++i) {
        lisAdiacenta.push_back(aux);
    }
}

Graf :: Graf(const int nrNoduriDat, const int nrMuchiiDat, const vector<vector<int>> &listaData)  //constructor parametrii - avem lista adiacenta
{
    nrNoduri = nrNoduriDat;
    nrMuchii = nrMuchiiDat;
    lisAdiacenta = listaData;
}

Graf :: Graf(const Graf & grafDat)   //constructor copiere
{
    nrNoduri = grafDat.nrNoduri;
    nrMuchii = grafDat.nrMuchii;
    lisAdiacenta = grafDat.lisAdiacenta;
}

///DESTRUCTOR
Graf :: ~Graf()
{
    lisAdiacenta.clear();
}

///GETTERI

int Graf :: getNrNoduri()    //getter numar noduri
{
    return nrNoduri;
}

int Graf :: getNrMuchii()    //getter numar muchii
{
    return nrMuchii;
}

///SUPRAINCARCARI OPERATORI
Graf& Graf :: operator= (const Graf &grafDat) //supraincarcare operator egal
{
    if(this != &grafDat) {
        this->nrNoduri = grafDat.nrNoduri;
        this->nrMuchii = grafDat.nrMuchii;

        if(!this->lisAdiacenta.empty())
            lisAdiacenta.clear();

        this->lisAdiacenta = grafDat.lisAdiacenta;
    }

    return *this;
}

ostream& operator<< (std::ostream& out, const Graf& grafDat)  //supraincarcare operator afisare
{
    out << "Numarul de noduri ale grafului este: " << grafDat.nrNoduri << "\n";
    out << "Numarul de muchii ale grafului este: " << grafDat.nrMuchii << "\n";

    for (int i = 1; i <= grafDat.nrNoduri; ++i) {
        out << i << ": ";
        for (int j = 1; j < grafDat.lisAdiacenta[i].size(); ++j) {
            out << grafDat.lisAdiacenta[i][j]<<" ";
        }
        out<<"\n";
    }

    return out;
}

///METODE CITIRI

void Graf :: citireNeorientat(istream &in)  //citim de la tastatura sau din fisier un graf neorientat
{
    int x, y;

    for(int i = 1; i <= nrMuchii; ++i) {
        in >> x >> y;
        lisAdiacenta[x].push_back(y), lisAdiacenta[y].push_back(x);
    }
}


void Graf :: citireOrientat(istream &in)   //citim de la tastatura sau din fisier un graf orientat
{
    int x, y;

    for(int i = 1; i <= nrMuchii; ++i) {
        in >> x >> y;
        lisAdiacenta[x].push_back(y);
    }
}

///METODE IMPLEMENTARE ALGORITMI

vector<int> Graf :: BFS(const int nodStart)     //parcurgere in latime
{
    queue<int> Q;
    int x, y;
    vector<int> distanta(nrNoduri+1, -1);

    distanta[nodStart] = 0;
    Q.push(nodStart);

    while(!Q.empty()) {
        x = Q.front();   //eliminam nodul curent din coada
        Q.pop();

        for (int i = 1; i < lisAdiacenta[x].size(); ++i)
            if (distanta[lisAdiacenta[x][i]] == -1) {              //daca nu a fost vizitat vecinul
                distanta[lisAdiacenta[x][i]] = distanta[x] + 1;    //inseamna ca am gasit drum mai scurt
                Q.push(lisAdiacenta[x][i]);
            }
    }

    return distanta;
}

void Graf :: afisareDistanteBFS(const int nodStart, ostream &out)   //afisam vectorul de distante de la BFS
{
    vector <int> distanta = BFS(nodStart);

    for(int i = 1; i <= nrNoduri; ++i) {
        out << distanta[i] << " ";
    }
}


void Graf :: DFS(const int x, vector<bool> &vizitat, stack<int> &stiva)   //parcurgere in adancime
{
    vizitat[x] = 1;

    for(int i = 1; i < lisAdiacenta[x].size(); i++)
        if(vizitat[lisAdiacenta[x][i]] == 0)    //daca vecinul sau nu a fost vizitat, mergem la el
            DFS(lisAdiacenta[x][i], vizitat, stiva);
    stiva.push(x);
}

int Graf :: nrCompConexe()   //numar de componente conexe facut cu DFS
{
    stack<int> stiva;
    int nrCompCon = 0;
    vector<bool> vizitat(nrNoduri+1, 0);

    for(int i = 1; i <= nrNoduri; ++i )
        if(!vizitat[i]) {
            nrCompCon++;
            DFS(i, vizitat, stiva);
        }

    return nrCompCon;
}

void Graf :: sortareTopologica(ostream &out)  //afisam o sortare topologica posibila
{
    stack<int> stiva;
    vector<bool> vizitat(nrNoduri+1, 0);

    for(int i = 1; i <= nrNoduri; ++i )
        if(!vizitat[i])
            DFS(i, vizitat, stiva);

    while (!stiva.empty()) {
        out << stiva.top() << " ";
        stiva.pop();
    }
}

void Graf :: existaGraf(vector<int> &grade, ostream &out)
{
    vector<int> copieGrade;
    copieGrade = grade;


    int S = 0; //suma grade
    for (int i = 0; i < grade.size(); ++i)
        S += grade[i];

    if (S % 2 == 1) {  //suma gradelor intr-un graf neorientat e mereu para
        out << "Nu\n";
        return;
    }

    sort(grade.begin(), grade.end(), greater<int>());  //luam gradele in ordine descrescatoare
    while (true) {

        if (grade[0] == 0) {
            out << "Da";
            return;
        }

        int fst = grade[0];
        grade.erase(grade.begin() + 0);
        if (fst > grade.size()) {  //daca avem un grad mai mare decat numarul de noduri ramase
            out << "Nu";
            return;
        }

        for (int i = 0; i < fst; ++i) {
             grade[i]--;
             if (grade[i] < 0) {
                out << "Nu";
                return;
            }
        }
        int j = fst;
        for (int i = 0; i < fst; ++i)   {
            if(j >= grade.size())
               break;
            if (grade[i] < grade[j]) {
                swap(grade[i], grade[j]);
                j++;
                }
        }
    }

}

void Graf::ctcDFS(int x, vector<int> &disc, vector<int> &low, stack<int> &stiva, vector<bool> &gasitStiva, vector<vector<int>> &rez)
{
    static int timp = 0;

    disc[x] = low[x] = ++timp;
    stiva.push(x);
    gasitStiva[x] = 1;


    for (int i = 1; i < lisAdiacenta[x].size(); i++) {
        if (disc[lisAdiacenta[x][i]] == -1)    {
            ctcDFS(lisAdiacenta[x][i], disc, low, stiva, gasitStiva, rez);
            low[x] = min(low[x], low[lisAdiacenta[x][i]]);
        }
        else if (gasitStiva[lisAdiacenta[x][i]] == 1)
            low[x] = min(low[x], disc[lisAdiacenta[x][i]]);
    }

    vector<int> compNoua;
    if (low[x] == disc[x]) {
        while (stiva.top() != x) {
            compNoua.push_back(stiva.top());
            gasitStiva[stiva.top()] = 0;
            stiva.pop();
        }

        compNoua.push_back(stiva.top());
        gasitStiva[stiva.top()] = 0;
        rez.push_back(compNoua);
        stiva.pop();
    }
}

void Graf :: CTC(ostream &out){
    vector<int> disc(nrNoduri+1, -1);
    vector<int> low(nrNoduri+1, -1);
    stack<int> stiva;
    vector<bool> gasitStiva(nrNoduri+1, 0);
    vector<vector<int>> rez;

    for (int i = 1; i <= nrNoduri; ++i) {
        if (disc[i] == -1)
            ctcDFS(i, disc, low, stiva, gasitStiva, rez);
    }

    out << rez.size() << "\n";
    for (int i = 0; i < rez.size(); ++i) {
        for (int j = 0; j < rez[i].size(); ++j) {
            out << rez[i][j] << " ";
        }
        out << "\n";
    }
}

void Graf::critConDFS(int x, vector<bool> &viz, vector<int> &disc, vector<int> &low, vector<int> &tata, ostream &out)
{
    static int timp = 0;

    viz[x] = 1;
    disc[x] = low[x] = ++timp;

    for (int i = 1; i < lisAdiacenta[x].size(); ++i) {
        if (!viz[lisAdiacenta[x][i]])    {
            tata[lisAdiacenta[x][i]] = x;
            critConDFS(lisAdiacenta[x][i], viz, disc, low, tata, out);
            low[x] = min(low[x], low[lisAdiacenta[x][i]]);

            if (low[lisAdiacenta[x][i]] > disc[x]) {
                    out << x << " " << lisAdiacenta[x][i] << "\n";
                }
        }
        else if (lisAdiacenta[x][i] != tata[x])
            low[x] = min(low[x], disc[lisAdiacenta[x][i]]);
    }
}

void Graf :: CriticalConnections(ostream &out) {
    vector<bool> viz(nrNoduri+1, 0);
    vector<int> disc(nrNoduri+1);
    vector<int> low(nrNoduri+1);
    vector<int> tata(nrNoduri+1, -1);

    for (int i = 1; i <= nrNoduri; ++i) {
        if (!viz[i])
            critConDFS(i, viz, disc, low, tata, out);
    }
}

void Graf :: biconexeDFS(int x, vector<int> &disc, vector<int> &low, stack<pair<int, int>> &comp, vector<int> &tata, vector<set<int>> &rez)
{
    static int timp = 0;

    disc[x] = low[x] = ++timp;
    int nrCopii = 0;

    for (int i = 1; i < lisAdiacenta[x].size(); ++i) {
        if (disc[lisAdiacenta[x][i]] == -1)    {
            nrCopii++;
            tata[lisAdiacenta[x][i]] = x;
            comp.push(make_pair(x, lisAdiacenta[x][i]));

            biconexeDFS(lisAdiacenta[x][i], disc, low, comp, tata, rez);

            low[x] = min(low[x], low[lisAdiacenta[x][i]]);
            if ((disc[x] == 1 && nrCopii > 1) || (disc[x] > 1 && low[lisAdiacenta[x][i]] >= disc[x])) {
            set<int> noduriCompNoua;
                    while (comp.top().first != x || comp.top().second != lisAdiacenta[x][i]) {
                    noduriCompNoua.insert(comp.top().first);
                    noduriCompNoua.insert(comp.top().second);
                    comp.pop();
                }
            noduriCompNoua.insert(comp.top().first);
            noduriCompNoua.insert(comp.top().second);
            rez.push_back(noduriCompNoua);
            comp.pop();
                }
        }
        else if (lisAdiacenta[x][i] != tata[x]) {
            low[x] = min(low[x], disc[lisAdiacenta[x][i]]);
            if (disc[lisAdiacenta[x][i]] < disc[x]) {
                comp.push(make_pair(x, lisAdiacenta[x][i]));
            }
        }
    }
}

void Graf :: Biconex(ostream &out) {
    vector<int> tata(nrNoduri+1, -1);
    vector<int> disc(nrNoduri+1, -1);
    vector<int> low(nrNoduri+1, -1);
    stack<pair<int, int>> comp;
    vector<set<int>> rez;

    for (int i = 1; i <= nrNoduri; ++i) {
        if (disc[i] == -1)
            biconexeDFS(i, disc, low, comp, tata, rez);

        bool compNoua = 0;
        set<int> noduriCompNoua;
        while (!comp.empty()) {
            compNoua = 1;
            noduriCompNoua.insert(comp.top().first);
            noduriCompNoua.insert(comp.top().second);
            comp.pop();
        }
        if (compNoua) {
            rez.push_back(noduriCompNoua);
        }
    }

    out << rez.size();

}

///Antete functii pentru rezolvarea problemelor
void Rezolva_DFSComponenteConexe();   //https://infoarena.ro/problema/dfs - 100pc
void Rezolva_BFS();                   //https://www.infoarena.ro/problema/bfs - 100pc
void Rezolva_SortareTopologica();     //https://infoarena.ro/problema/sortaret - 100pc
void Rezolva_Havel_Hakimi();          //exemple: (DA:(5 5 5 5 5 5),(5 5 5 5 4 4),(3 3 3 3),(4 4 4 4 4),(2 2 1 1),(2 2 1 1 0),(2 0 1 2 1),(2 1 2 1 2 1 2 3)
                                      //(NU:(5 5 5 5 5 4),(3 2 1 0), (3 3 3 3 3)
void Rezolva_CTC();
void Rezolva_Critical_Connection();
void Rezolva_Biconex();

///Driver code
int main()
{
    Rezolva_Biconex();
    return 0;
}


///Corpurile functiilor
void Rezolva_DFSComponenteConexe()
{
    ifstream fin("dfs.in");
    ofstream fout("dfs.out");

    int N, M;
    fin >> N >> M;

    Graf graf(N, M);
    graf.citireNeorientat(fin);

    fout<<graf.nrCompConexe();
}

void Rezolva_BFS()
{
    ifstream fin("bfs.in");
    ofstream fout("bfs.out");

    int N, M, S;
    fin >> N >> M >> S;

    Graf graf(N, M);
    graf.citireOrientat(fin);

    graf.afisareDistanteBFS(S, fout);
}

void Rezolva_SortareTopologica()
{
    ifstream fin("sortaret.in");
    ofstream fout("sortaret.out");

    int N, M;
    fin >> N >> M;

    Graf graf(N, M);
    graf.citireOrientat(fin);

    graf.sortareTopologica(fout);
}

void Rezolva_Havel_Hakimi()
{
    ifstream fin("havelhakimi.in");
    ofstream fout("havelhakimi.out");

    vector<int> grade;
    int N, x;
    fin >> N;

    for (int i = 0; i < N; i++) {
        fin >> x;
        grade.push_back(x);
    }
    Graf :: existaGraf(grade, fout);
}

void Rezolva_CTC()
{
    ifstream fin("ctc.in");
    ofstream fout("ctc.out");

    int N, M;
    fin >> N >> M;

    Graf graf(N, M);
    graf.citireOrientat(fin);

    graf.CTC(fout);
}

void Rezolva_Critical_Connection()
{
    ifstream fin("critcon.in");
    ofstream fout("critcon.out");

    int N, M;
    fin >> N >> M;

    Graf graf(N, M);
    graf.citireNeorientat(fin);

    graf.CriticalConnections(fout);
}

void Rezolva_Biconex()
{
    ifstream fin("biconex.in");
    ofstream fout("biconex.out");

    int N, M;
    fin >> N >> M;

    Graf graf(N, M);
    graf.citireNeorientat(fin);

    graf.Biconex(fout);
}