Cod sursa(job #2796712)

Utilizator redikusTiganus Alexandru redikus Data 8 noiembrie 2021 18:31:14
Problema Componente tare conexe Scor 10
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 14.28 kb
#include <iostream>
#include <fstream>
#include <bits/stdc++.h>

using namespace std;

class graf {

    int noduri, muchii;
    vector < vector < int >> adiacenta;

public:
    // Constructor cu matrice de adiacenta data
    graf(vector < vector < int >> listaAdiacenta, int noduri, int muchii): adiacenta(listaAdiacenta), noduri(noduri), muchii(muchii) {};

    // Constructor fara matrice de adiacenta, se cu initalizeaza una goala
    graf(int noduri, int muchii): adiacenta(noduri + 1), noduri(noduri), muchii(muchii) {};

    void citireNeorientat(istream & in ) {
        for (int i = 0; i < muchii; i++) {
            int aux1, aux2; in >> aux1 >> aux2;
            adiacenta[aux1].push_back(aux2);
            adiacenta[aux2].push_back(aux1);
        }
    }

    void citireOrientat(istream & in ) {
        for (int i = 0; i < muchii; i++) {
            int aux1, aux2; in >> aux1 >> aux2;
            adiacenta[aux1].push_back(aux2);
        }
    }

    vector < int > bfs(int start) {
        vector < int > rasp(noduri + 1, -1);
        vector < int > vis(noduri + 1);
        queue < int > q;
        vis[start] = 1;
        q.push(start);
        rasp[start] = 0;

        // Se baga pe rand in queue toate nodurile nevizitate ale nodului din capul queue-ului, si se noteaza timpul la care se ajunge la ele
        while (!q.empty()) {
            int curr = q.front();
            q.pop();
            for (int i: adiacenta[curr])
                if (vis[i] == 0) {
                    vis[i] = 1;
                    q.push(i);
                    rasp[i] = rasp[curr] + 1;
                };
        }
        return rasp;
    }

    int dfs() {
        vector < int > vis(noduri + 1);
        int res = 0;
        stack < int > s;


        // Se baga pe rand in stack toate nodurile nevizitate ale nodului din capul queue-ului, si se noteaza timpul la care se ajunge la ele. Se simuleaza call stack-ul de la recursivitate de dfs
        for (int i = 1; i <= noduri; i++) {
            if (vis[i] == 0) {
                res++;
                vis[i] = 1;
                s.push(i);
                while (!s.empty()) {
                    int curr = s.top();
                    s.pop();
                    for (int i = adiacenta[curr].size() - 1; i >= 0; i--) {
                        int nod = adiacenta[curr][i];
                        if (vis[nod] == 0) {
                            vis[nod] = 1;
                            s.push(nod);
                        }
                    }
                }
            }
        }
        return res;
    }

    void dfsbiconex(int tata, vector < int > & timp, vector < int > & rev, stack < pair < int, int >> & s, int & timpcurent, vector < string > & rasp) {
        // Tarjan modificat
        timpcurent++;
        timp[tata] = timpcurent;
        rev[tata] = timpcurent;
        int fiuRadacina = 0;

        // Se tin minte timpii de intoarcere respectiv timpul de intalnire al fiecarui nod in arborele de dfs call
        for (int fiu: adiacenta[tata]) {
            if (timp[fiu] == -1) {
                // Se retine cati fii are fiecare nod in arborele de call dfs
                fiuRadacina++;
                // Se parcurge prin dfs fiecare nod, si cand se gaseste un nod nevizitat se adauga muchia intr-un stack
                s.push(make_pair(tata, fiu));
                dfsbiconex(fiu, timp, rev, s, timpcurent, rasp);
                // Timpul de revenire al unei muchii este minimul dintre timpul de revenire curent si timpul de revenire al fiului, pt ca daca fiul are timp de revenire mai mic si tata il va putea accesa
                rev[tata] = min(rev[tata], rev[fiu]);

                if ((timp[tata] != 1 && rev[fiu] >= timp[tata]) || (timp[tata] == 1 && fiuRadacina > 1)) {
                    // Se verifica daca un nod e critic, si sunt 2 cazuri. Primul e cand nodul nu e chiar nodul de incepere al dfs, iar timpul de revenire al fiului este mai mare ca tatal.
                    // Practic cand nu suntem intr-un ciclu. Al doilea caz este cel discutat la laborator, cand nodul este chiar radacina arborelui, daca are 2 fii atunci e clar nod critic
                    pair < int, int > stop = make_pair(tata, fiu);
                    unordered_set < int > aux;
                    string str = "";

                    // Se face afisare cu string
                    aux.insert(stop.first);
                    aux.insert(stop.second);
                    str += to_string(stop.first);
                    str += " ";
                    str += to_string(stop.second);
                    str += " ";
                    // Se parcurge stackul de muchii pana cand dam de muchia care leaga fiul de tata. Se face asta pt ca mai intai se va adauga o muchie intre fiu si tata in stack, apoi se va face dfs
                    // si se vor detecta componentele biconexe ale descendentilor si se vor adauga in stack muchiile descendentilor, iar cad se va iesi din dfs-ul descendentilor unui nod tata
                    // ce vor ramane in stack vor fi chiar muchiile corespunzatoare componentei biconexe, pana la muchia care leaga tatal de fiu
                    while (s.top() != stop) {
                        int nodcur = s.top().first;
                        if (aux.find(nodcur) == aux.end()) {
                            str += to_string(nodcur);
                            str += " ";
                            aux.insert(s.top().first);
                        }
                        s.pop();
                    }
                    str += '\n';
                    rasp.push_back(str);
                    s.pop();
                }
            }
            else {
                // Daca nodul e deja vizitat, atunci am detectat o muchie de intoarcere, si timpul de revenire al tatalui devine minimul dintre timpul actual de revenire (ca poate fi mai mic, cu o alta muchie gasita deja)
                // si timpul de gasire al fiului
                rev[tata] = min(rev[tata], timp[fiu]);
                // Verificam sa nu fie o muchie care sa duca in fata (in arbore) de fapt, pt ca deja a fost analizata mai devreme in dfs
                if (timp[fiu] < timp[tata]) {
                    s.push(make_pair(tata, fiu));
                }
            }
        }
    }

    vector < string > biconex() {
        vector < int > timp(noduri + 1, -1), rev(noduri + 1);
        stack < pair < int, int >> s;
        vector < string > rasp;
        int timpo = 0;

        // Se se proneste dfs-ul din toate componentele conexe, si apoi se adauga la raspuns si ce a mai ramas in stack, pt ca si ce ramane va forma o componenta biconexa
        for (int i = 0; i < noduri; i++) {
            if (timp[i] == -1) {
                dfsbiconex(i, timp, rev, s, timpo, rasp);
            }
            if (!s.empty()) {
                unordered_set < int > aux;
                string str;

                while (!s.empty()) {
                    if (aux.find(s.top().first) == aux.end()) {
                        aux.insert(s.top().first);
                        str += to_string(s.top().first);
                        str += " ";
                    }
                    if (aux.find(s.top().second) == aux.end()) {
                        aux.insert(s.top().second);
                        str += to_string(s.top().second);
                        str += " ";
                    }
                    s.pop();
                }
                str += '\n';
                rasp.push_back(str);
            }
        }
        return rasp;
    }

    void dfsCtc(int tata, vector < int > & timp, vector < int > & rev, stack < int > & s, int & timpcurent, vector < string > & rasp, unordered_set < int > & check) {
        // Tarjan
        timpcurent++;
        timp[tata] = timpcurent;
        rev[tata] = timpcurent;
        s.push(tata);
        check.insert(tata);

        // Se tin minte timpii de intoarcere respectiv timpul de intalnire al fiecarui nod in arborele de dfs call
        for (int fiu: adiacenta[tata]) {
            if (timp[fiu] == -1) {
                // Cand descoperim un fiu nevizitat facem dfs si
                dfsCtc(fiu, timp, rev, s, timpcurent, rasp, check);
                // Timpul de revenire al unei muchii este minimul dintre timpul de revenire curent si timpul de revenire al fiului, pt ca daca fiul are timp de revenire mai mic si tata il va putea accesa
                rev[tata] = min(rev[tata], rev[fiu]);
            }
            else if (timp[fiu] < timp[tata]) {
                rev[tata] = min(rev[tata], timp[fiu]);
            }
        }
        if (timp[tata] == rev[tata]) {
            string aux = "";
            while (s.top() != tata) {
                aux += to_string(s.top());
                aux += " ";
                check.erase(s.top());
                s.pop();
            }
            aux += to_string(s.top());
            aux += " ";
            check.erase(s.top());
            s.pop();
            aux += '\n';
            rasp.push_back(aux);
        }
    }

    vector < string > ctc() {
        vector < int > timp(noduri + 1, -1), rev(noduri + 1);
        unordered_set < int > check;
        stack < int > s;
        vector < string > rasp;
        int timpo = 0;

        for (int i = 1; i <= noduri; i++) {
            if (timp[i] == -1) {
                dfsCtc(i, timp, rev, s, timpo, rasp, check);
            }
        }
        return rasp;
    }

    void dfsSortaret(int tata, vector < int > & vis, vector < int > & res) {
        for (int fiu: adiacenta[tata]) {
            if (!vis[fiu]) {
                vis[fiu] = 1;
                dfsSortaret(fiu, vis, res);
            }
        }

        res.push_back(tata);
    }

    vector < int > sortaret() {
        vector < int > vis(this -> noduri + 1);
        vector < int > res;

        for (int i = 1; i <= this -> noduri; i++) {
            if (vis[i] == 0) {
                vis[i] = 1;
                dfsSortaret(i, vis, res);
            }
        }
        return res;
    }

    void dfsCriticalConnections(int tata, vector < int > & timp, vector < int > & rev, int & timpcurent, vector < vector < int >> & rasp, vector < int > & parinte) {
        timpcurent++;
        timp[tata] = timpcurent;
        rev[tata] = timpcurent;

        for (int fiu: adiacenta[tata]) {
            parinte[fiu] = tata;
            if (timp[fiu] == -1) {
                dfsCriticalConnections(fiu, timp, rev, timpcurent, rasp, parinte);
                rev[tata] = min(rev[tata], rev[fiu]);
                if (rev[fiu] > timp[tata]) {
                    vector < int > aux;
                    aux.push_back(tata);
                    aux.push_back(fiu);
                    rasp.push_back(aux);
                }
            }
            else if (parinte[tata] != fiu) {
                rev[tata] = min(rev[tata], timp[fiu]);
            }
        }
    }

    vector < vector < int >> criticalConnections() {
        vector < int > timp(noduri + 1, -1), rev(noduri + 1), parinte(noduri + 1);
        vector < vector < int >> rasp;
        int timpo = 0;

        for (int i = 1; i <= noduri; i++) {
            if (timp[i] == -1) {
                dfsCriticalConnections(i, timp, rev, timpo, rasp, parinte);
            }
        }
        return rasp;
    }
};

bool havelHakimi(vector < int > & a) {
    sort(a.begin(), a.end(), [](int m, int n) {
        return m > n;
    });
    int x = a[0];

    if (a.size() == 1 && x >= 1) {
        return false;
    }
    if (x == 0) {
        return true;
    }

    a.erase(a.begin() + 0);

    if (x > a.size()) {
        return false;
    }
    for (int i = 0; i < x; i++) {
        a[i]--;
        if (a[i] < 0) {
            return false;
        }
    }
    return havelHakimi(a);
}

void bfsDriver() {
    //citire
    ifstream in ("bfs.in");
    ofstream out("bfs.out");

    int n, m, s; in >> n >> m >> s;
    graf x(n, m);

    x.citireOrientat( in );

    //afisare
    vector < int > rasp = x.bfs(s);
    for (int i = 1; i <= n; i++) {
        out << rasp[i] << " ";
    }

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

void dfsDriver() {
    //citire
    ifstream in ("dfs.in");
    ofstream out("dfs.out");

    int n, m; in >> n >> m;
    graf x(n, m);

    x.citireNeorientat( in );

    //afisare
    out << x.dfs();

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

void biconexDriver() {
    //citire
    ifstream in ("biconex.in");
    ofstream out("biconex.out");

    int n, m; in >> n >> m;
    graf x(n, m);

    x.citireNeorientat( in );

    //afisare
    vector < string > fin = x.biconex();
    out << fin.size() << '\n';
    for (string i: fin) {
        out << i;
    }

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

void ctcDriver() {
    //citire
    ifstream in ("ctc.in");
    ofstream out("ctc.out");

    int n, m; in >> n >> m;
    graf x(n, m);

    x.citireOrientat( in );

    //afisare
    vector < string > fin = x.ctc();
    out << fin.size() << '\n';
    for (string i: fin) {
        out << i;
    }

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

void sortaretDriver() {
    //citire
    ifstream in ("sortaret.in");
    ofstream out("sortaret.out");

    int n, m; in >> n >> m;
    graf x(n, m);

    x.citireOrientat( in );

    //afisare
    vector < int > res = x.sortaret();
    for (int i = res.size() - 1; i >= 0; i--) {
        out << res[i] << " ";
    }

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

void havelHakimiDriver() {
    //citire
    ifstream in ("havelhakimi.in");
    ofstream out("havelhakimi.out");

    int n; in >> n;
    vector < int > a;

    //afisare
    for (int i = 0; i < n; i++) {
        int aux; in >> aux;
        a.push_back(aux);
    }
    out << havelHakimi(a);

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

void criticalConnectionsDriver() {
    //citire
    int n, m;
    cin >> n >> m;
    graf x(n, m);

    x.citireNeorientat(cin);

    //afisare
    vector < vector < int >> fin = x.criticalConnections();
    for (auto i: fin) {
        for (auto j: i) {
            cout << j << " ";
        }
    }
}

int main() {
    //Se apeleaza functia corespunzatoare problemei
    ctcDriver();
    return 0;
}