Cod sursa(job #2792638)

Utilizator MirunaStefaniaLupascu Miruna-Stefania MirunaStefania Data 2 noiembrie 2021 08:11:15
Problema BFS - Parcurgere in latime Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 11.91 kb
#include <bits/stdc++.h>
#define N 100005    ///the maximum number of nodes in the graph


using namespace std;

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

queue<int> q;

int ctComponents = 0;
vector<int> comp[N]; //to print the strongly connected components

class Graph {
private:
    int n, m;

    vector<int> adlist[N];  //adjent list
    bool viz[N] = {0};
    int dist[N] = {0};      //the minuimum distance from a particular vertex to all others

    stack<int> s; //final times in dfs

    void dfCritical(int k, int father, int level[], int level_min[], vector<vector<int>>& sol); // dfs used in the algorithm for critical edges
    void dfBiconnected(int k, int father, int level[N], int level_min[N], vector<vector<int>> &biconnected, pair<int, int> stackk[], int &vf_stack); //dfs used in the algorithm for biconnected components

public:
    Graph() = default;
    Graph(int n, int m):n(n), m(m){}

    void readDirected();
    void readUndirected();

    void bfs(int first);   //for minimum path
    void dfs(int first);   //for connected components
    void dfsT(int first); //used only for Transpoused --> do not add nodes in s, print the node
                          //we will use "viz" from the transpoused graph
    void printDist();
    void connectedComponents();
    void printGraph();
    Graph transpose();
    void stronglyConnectedComponents();
    void sortTopo(); //dfs and we keep the final times, after a node is finished, we put it in the stack

    bool graphExistsHakimi(vector<int> &dg, int n); //the grades and number of nodes

    void biconnectedComponents();

    vector<vector<int>> criticalConnections(int n, vector<vector<int>>& connections); /*Input: n = 2, connections = [[0,1]] Output: [[0,1]]*/

};


void Graph::readDirected() {
    for(int i = 1; i <= m; ++i) {
        int x, y;
        fin >> x >> y;
        adlist[x].push_back(y);
    }
}

void Graph::readUndirected() {

    for(int i = 1; i <= m; ++i) {
        int x, y;
        fin >> x >> y;
        adlist[x].push_back(y);
        adlist[y].push_back(x);
    }
}

void Graph::printGraph() {
    for(int i = 1; i <= n; ++i) {
        fout << i <<":";
        for(int j = 0; j < adlist[i].size(); ++j)
            fout << adlist[i][j] << " ";
        fout <<"\n";

    }
}

void Graph::bfs(int first) {
    ///bfs detemines the shortest path
    int node, dim;
    dist[first] = 1;
    viz[first] = 1;
    q.push(first);

    while(!q.empty())   //for each node add all his neighbors that haven't been visisted yet & update minimum distance
    {
        node = q.front();
        q.pop();
        dim = adlist[node].size();
        for(int i = 0; i < dim; ++i)
            if(!viz[adlist[node][i]])
        {
            cout << adlist[node][i] <<" ";
            viz[adlist[node][i]] = 1;
            dist[adlist[node][i]] = dist[node] + 1;
            q.push(adlist[node][i]);
        }
    }
}

void Graph::dfs(int node){
    int i, dim;
    viz[node] = 1;
    dim = adlist[node].size();
    for(i = 0; i < dim; ++i)
            if(!viz[adlist[node][i]])
                dfs(adlist[node][i]);
    s.push(node);
}

void Graph::printDist(){
    int i;
    for(i = 1; i <= n; ++i)
        fout << dist[i] - 1 << " ";
}

void Graph::connectedComponents() {
    ///a crossing with a dfs is a connected component
    int i, nr = 0;
    for(i = 1; i <= n; ++i)
        if(!viz[i])
    {
        nr++;
        dfs(i);
    }
    fout << nr;

}

void Graph::dfsT(int node){
    int i, dim;

    comp[ctComponents].push_back(node);//is part of the same component

    viz[node] = 1;
    dim = adlist[node].size();
    for(i = 0; i < dim; ++i)
            if(!viz[adlist[node][i]])
                dfsT(adlist[node][i]);

}

Graph Graph::transpose() {
    int i, j;
    Graph gt(n, m);
    for(i = 1; i <= n; ++i)
        for(j = 0; j < adlist[i].size(); ++j)
            gt.adlist[adlist[i][j]].push_back(i);
    return gt;

}

void Graph::stronglyConnectedComponents(){
///1 g transpouse = gt
///2 dfs g --> end times --> add in stack
///3 dfs on gt in descending order of end times(just substract from the stack)
///the nodes from a crossing = strongly connected component

    int node;
    for(int i = 1; i <= n; ++i)
        if(!viz[i])
            this->dfs(i);
    Graph gt = this->transpose();
    while(!s.empty())
    {
        node = s.top();
        s.pop();
        if(!gt.viz[node])
            {
                ctComponents++;
                gt.dfsT(node);
            }
    }

    int i, j;
    fout << ctComponents << "\n";

    for(i = 1; i <= ctComponents; ++i) {
        for(j = 0; j < comp[i].size(); ++j)
            fout <<comp[i][j] << " ";
        fout << "\n";
            }

}

void Graph::sortTopo(){
///condition : if exist edge u-->v then u is BEFORE v in topological sort
///determine the end times with dfs --> add them in a stack --> our solution
///if exist u->v ==> end_time[u] > end_time[v]

    for(int i = 1; i <= n; ++i)
        if(!viz[i])
            dfs(i);
    while(!s.empty())
    {
        fout << s.top() <<" ";
        s.pop();
    }

}

bool Graph::graphExistsHakimi(vector<int> &dg, int n) {
    ///sort the vector of degrees desc
    ///we start with the biggest degree v ant link it with the next v nodes (substract 1 from the next v elements)
    ///repeat until:
    ///1. all the remaining elements are 0 (graph exists)
    ///2. negative values encounter after substraction (doesn't exist)
    ///3. not enough elements remaining after substraction (doesn't exist)

    while(1)
    {
        sort(dg.begin(), dg.end(), greater<>());
        if(dg[0] == 0)
            return true; //all elements equal to 0
        int degree = dg[0];
        dg.erase(dg.begin() + 0); //delete the first element

        if(degree > dg.size())//check if enough elements are in the list
            return false;

        for(int i = 0; i < dg.size(); ++i)  //substract 1 from the following
        {
            dg[i]--;
            if(dg[i] < 0)   //check negative
                return false;
        }
    }
}

void Graph::dfCritical(int k, int father, int level[], int level_min[],  vector<vector<int>>& sol){
    ///dfs and keep the level and minimum level that we can reach from a node
    ///when we find " level[k] < level_min[node] " where node = child, it means that we need that edge to reach the ancestors--> critical edge

    if( father == -1)
        level[k] = 1;
    else
        level[k] = level[father] + 1;
    level_min[k] = level[k];

    int dim = adlist[k].size();
    for (int i = 0; i < dim; ++i)
    {
        int node = adlist[k][i];
        if(level[node])//if visited
        {
            if(node != father && level[node] < level_min[k])   //return edge --> check if we can reach a higher level
                level_min[k] = level[node];
        }
        else
        {

            dfCritical(node, k, level, level_min, sol);    //continue dfs

            if(level_min[k] > level_min[node]) //one of the childs has a return edge
                level_min[k] = level_min[node];


            ///determine critical connections
            if(level[k] < level_min[node])  //we can not reach that level or a higher level with a return edge
                {
                vector<int> current;
                current.push_back(node);
                current.push_back(k);
                sol.push_back(current);
                }
        }
    }

}

vector<vector<int>> Graph :: criticalConnections(int n, vector<vector<int>>& connections){
    int level[N] = {0};
    int level_min[N] = {0};

    for(int i = 0; i < connections.size(); ++i)//for each edge
    {
        adlist[connections[i][0]].push_back(connections[i][1]);
        adlist[connections[i][1]].push_back(connections[i][0]);
    }
    vector<vector<int>> sol;//solution of critical edges

    dfCritical(0, -1, level, level_min, sol);
    return sol;

}

void Graph::biconnectedComponents(){

    ///dfs and keep adding nodes in the stack until we finish the biconnected component
    ///keep the level and minimum level that we can reach from a node
    ///when we find " level_min[node] >= level[k] " where node = child, k = father we have to substract all the elements until k from the stack --> a new biconnected component

    int level[N] = {0};
    int level_min[N] = {0};

    vector<vector<int>> biconnected;//vector with the components
    pair<int, int> stackk[N * 2];// a stack  with the nodes visited in dfs(added by their edges)
                                // we have to keep edges bcs the articulation points are part of more biconnecte components
    int vf_stack = 0;


    dfBiconnected(1, 0, level, level_min, biconnected, stackk, vf_stack);

    fout << biconnected.size() << "\n";

    for(int i = 0; i < biconnected.size(); ++i)
    {
        vector <int> comp = biconnected[i];
        for(int j = 0 ; j < comp.size(); ++j)
            fout << comp[j] <<" ";
        fout <<"\n";
    }


}

void Graph::dfBiconnected(int k, int father, int level[N], int level_min[N], vector<vector<int>> &biconnected, pair<int, int> stackk[], int &vf_stack){
    level[k] = level[father] + 1;
    level_min[k] = level[k];

    int dim = adlist[k].size();
    for (int i = 0; i < dim; ++i)
    {
        int node = adlist[k][i];
        if(level[node])//if visited
        {
            if(node != father && level[node] < level_min[k])   //return edge --> check if we can reach a higher level
                level_min[k] = level[node];
        }
        else
        {
           stackk[++vf_stack] = {k, node};  //add in dfs order
            dfBiconnected(node, k, level, level_min, biconnected, stackk, vf_stack);    //continue dfs

            if(level_min[k] > level_min[node]) //one of the childs has a return edge
                level_min[k] = level_min[node];

            if(level_min[node] >= level[k]) //the condition that the biconnected component is complete
            {
                biconnected.push_back({});  //create e new biconnected component
                while(stackk[vf_stack].first != k)  //add all nodes from the stack until k
                    biconnected.back().push_back(stackk[vf_stack--].second);    //add at the last component the nodes
                biconnected.back().push_back(stackk[vf_stack].second);
                biconnected.back().push_back(stackk[vf_stack].first);   //add for the last edge both nodes the articulation point is part of more components
                vf_stack--;
            }
        }
    }

}
int main()
{
    int i, first, n, m;


    fin >> n >> m >> first;
    Graph g(n, m);

///MINIMUM DISTANCE

    g.readDirected();
    g.bfs(first);
    g.printDist();


/// CONNECTED COMPONENTS
/*
    g.readUndirected();
    g.connectedComponents();
*/

///STRONGLY CONNECTED COMPONENTS
///time limit exceeded pe un test
/*  g.readDirected();
    g.stronglyConnectedComponents();
*/

///TOPOLOGICAL SORT
/*
    g.readDirected();
    g.sortTopo();
*/

///HAVEL-HAKIMI
    /*
    vector<int> dg;
    fin >> n;
    Graph g(n, 0);
    for(int i = 1; i <= n; ++i)
    {
        fin >> first;
        dg.push_back(first);
    }
    if(g.graphExistsHakimi(dg, n))
        fout << "yes";
    else fout << "no";
*/

///CRITICAL CONNECTIONS
/*
    //fin >> n;
    n = 2;
    Graph g(n, 0);
    vector<vector<int>>connections = {{0,1}};
    vector<vector<int>> sol = g.criticalConnections(n, connections);
    fout << sol.size() << "\n";
    for(int i = 0; i < sol.size(); ++i)
    {
        for(int j = 0; j < sol[i].size(); ++j)
            fout << sol[i][j] << " ";
        fout <<"\n";
    }
*/

///BICONNECTED COMPONENTS
/*
    fin >> n >> m;
    Graph g(n, m);
    g.readUndirected();
    g.biconnectedComponents();

*/


    return 0;
}