Cod sursa(job #2792077)

Utilizator dascalu_maraDascalu Mara Elena dascalu_mara Data 31 octombrie 2021 20:25:49
Problema Componente tare conexe Scor 10
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 7.33 kb
//
//  main.cpp
//  Componente tare conexe
//
//  Created by Mara Dascalu on 31/10/2021.
//

#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <stack>
#include <bits/stdc++.h>
#include <map>
#include <list>
#include <set>




using namespace std;

ifstream input("ctc.in");
ofstream output("ctc.out");

class Graph
{
    int nodes, edges;
    vector<int> adj[100010] ;
    int cost[1001];
    queue<int> queue_bfs;
    int level[100010] = {0};
    int low_level[100010] = {0};
    stack<pair<int, int>> component_node;
    vector<int> vec_scc[100010];

public:

    bool visited[100010] = {0};
    vector<int> bcc[100010]; //vectorul care stocheaza componentele biconexe
    int current = 0;

   void set_no_nodes(int n) {nodes = n;}
   int get_no_nodes() {return nodes;}
   void set_no_edges(int n) {edges = n;}
   int get_no_edges() {return edges;}

   void addEdge_dg ()
   {
       int no_nodes, no_edges;
       input>>no_nodes>>no_edges;
       set_no_nodes(no_nodes);
       
       int node1, node2;
       
       for(int i = 0 ; i < no_edges; i++)
       {
           input>>node1>>node2;
           adj[node1].push_back(node2);
       }
       
       
   }

   void addEdge_ug ()
   {
       int no_nodes, no_edges;
       input>>no_nodes>>no_edges;
       
       int node1, node2;
       
       for(int i = 0 ; i < no_edges; i++)
       {
           input>>node1>>node2;
           adj[node1].push_back(node2);
           adj[node2].push_back(node1);
       }
   }

   void DFS(int node)
   {
       visited[node] = 1;
       output<<node<<" ";

       for (int i = 0; i < adj[node].size(); i++)
           if( !visited[adj[node][i]])
               DFS(adj[node][i]);
   }

   void afis_adj(int node){
       for (int i = 0; i < adj[node].size(); i++)
            cout<<adj[node][i]<<" ";
   }


   void BFS (int node)
   {
       memset(cost,  -1, sizeof(cost));
       visited[node] = 1; //marchez nodul curent ca vizitat
       queue_bfs.push(node);
       cost[node] = 0;

       while (!queue_bfs.empty()) {
           node = queue_bfs.front(); //iau nodul din varful cozii
           queue_bfs.pop();

           for (int i = 0; i < adj[node].size(); i++) //parcurg toti vecinii sai
               if ( !visited[adj[node][i]]) //daca sunt nevizitati
               {
                   visited[adj[node][i]] = 1;  //ii marchez ca vizitati
                   queue_bfs.push(adj[node][i]);   //ii adaug in coada
                   cost[adj[node][i]] = cost[node] + 1;   //calculez costul raportat la "parintele" sau
               }
       }
   }

   void out_cost (int no)
   {
       for (int i = 1; i <= no; i++)
       output<<cost[i]<<" ";
   }

   void DFS(int node, int parent)
{
   visited[node] = 1;


   level[node] = level[parent] + 1;
   low_level[node] = level[node];
   int child;

   int dim = adj[node].size();
   for ( int i = 0; i< dim ; i++)
   {


       child = adj[node][i];
       if (child != parent)
       {
           if (visited[child] == true)  //daca fiul sau a fost deja parcurs si nu este tatal nodului curent, muchia (fiu,nod) este muchie de intoarcere
           {
               //cout<<"true "<<node<<" "<<*iter<<" "<<level[*iter]<<"\n";
               if(level[child] < low_level[node])low_level[node] = level[child];  //actualizam valoarea low_level[nod] daca fiul sau se afla mai sus decat el (p[t ca avem muchie de intoarcere
           }
           else //daca fiul sau nu a fost inca parcurs, continuam DFS din fiu
           {
               component_node.push({node, child});
               //cout<<"inainte de dfs"<<node<<" "<<*iter<<" "<<level[*iter]<<"\n";
               DFS(child, node);

               //cout<<"dupa dfs"<<*iter<<" "<<level[*iter]<<"\n";
               if (low_level[child] < low_level[node])
                   low_level[node] = low_level[child]; //daca la intoarcerea din apel fiul are un nivel de intoarcere mai mic decat al nodului, actualizam low_level[node]

               if (low_level[child] >= level[node])
               {
                   while( component_node.top().first != node)
                   {
                       bcc[current].push_back(component_node.top().second);
                       component_node.pop();
                   }
                   bcc[current].push_back(component_node.top().second);
                   bcc[current].push_back(component_node.top().first);
                   component_node.pop();
                   //bcc[current].push_back(node);
                   current++;

               }




           }
       }
   }
}
    
    void sccUtil (int node, int disc[], int low[], stack<int> *st, bool stackMember[])
    {
        static int time = 0;
        
        //initializare disc si low pentru nodul curent
        disc[node] = low[node] = time++;
        st->push(node);
        stackMember[node] = true;
        
        //parcurgem toti vecinii lui node
        for (int i = 0; i < adj[node].size(); i++)
        {
            int adj_node = adj[node][i];
            
            if (!disc[adj_node])  //daca vecinul nu a fost vizitat inca
            {
                sccUtil(adj_node, disc, low, st, stackMember);
                
                low[node] = min(low[node], low[adj_node]); //verificam daca subarborele care are drep radacina adj_node are un drum catre un stramos al lui node
            }
            else if (stackMember)
            {
                low[node] = min(low[node], disc[adj_node]);  //facem update daca avem muchie de intoarcere
            }
        }
        
        int extractedNode = 0;
        if (low[node] == disc[node])  //conditia ca un nod sa fie radacina unei componente tare conexe
        {
            while (st->top() != node) {
                extractedNode = (int) st->top();
                st->pop();
//                cout<<extractedNode<<" ";
                vec_scc[current].push_back(extractedNode);
                stackMember[extractedNode] = false;
            }
            extractedNode = st->top();
            st->pop();
//            cout<<extractedNode<<"\n";
            vec_scc[current].push_back(extractedNode);
            sort(vec_scc[current].begin(), vec_scc[current].end());
            stackMember[extractedNode] = false;
            current++;
        }
    }
    
    void scc()
    {
        int dim = get_no_nodes();
        int *disc = new int[dim]; //memoreaza timpul de descoperire al fiecarui nod
        int *low = new int[dim]; //memoreaza timpul de descoperire minim care poate fi accesat din subarborele care are radacina in fiecare nod
        bool *stackMember = new bool[dim]; //pentru verificarea mai rapida daca un nod este sau nu in stiva
        stack<int> *st = new stack<int>();  //pentru stocarea compo\ conexe
        
        for (int i = 0; i < dim ; i++)
        {
            disc[i] = low[i] = 0;
            stackMember[i] = false;
        }
        
        //apelam recursiv sccUtil pentru gasirea comp tare conexe
        for (int i =01; i < dim; i++)
            if(!disc[i])
                sccUtil(i, disc, low, st, stackMember);
    }

    void output_scc ()
    {
        output<<current<<"\n";
        for (int i = current - 1; i >= 0 ; i--)
        {
            for (int j = 0; j < vec_scc[i].size(); j++)
                output<<vec_scc[i][j]<<" ";
            output<<"\n";
        }
    }
}g;

int main(int argc, const char * argv[]) {
    g.addEdge_dg();
    g.scc();
    g.output_scc();
    return 0;
}