Cod sursa(job #2797944)

Utilizator faalaviaFlavia Podariu faalavia Data 10 noiembrie 2021 19:29:59
Problema Componente biconexe Scor 90
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 14.65 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>
#include <sys/resource.h>
using namespace std;

class Graph {
    int nrNodes; //number of nodes
    vector<vector<pair<int, double>>> edges; // list of connections between nodes
public:
    Graph(int _nrNodes);
    int getNrNodes() const;
    void setEdge(int node, int neighbour, double cost);
    void printEdges() const;
    int nrConnectedComponents();
    const vector<pair<int, double>>& getNeighbours(int node);
    virtual ~Graph() = default;


private:
    void DFS(int node, vector<int>& visited);
};

//---------------------------------------------------------

Graph::Graph(int _nrNodes)
{
    this -> nrNodes = _nrNodes;
    this -> edges.resize(_nrNodes+1);
    /*
     * Nodes start at 1, but index starts at 0
     */
}

int Graph::getNrNodes() const
{
    return this -> nrNodes;
}

void Graph::setEdge(int node, int neighbour, double cost)
{
    this -> edges[node].push_back({make_pair(neighbour, cost)});
}

const vector<pair<int, double>>& Graph::getNeighbours(int node)
{
    return this -> edges[node];
}

int Graph::nrConnectedComponents()
{
    int ans = 0;
    vector<int> visited(this -> nrNodes+1, 0);
    for(int i = 1 ; i <= this -> nrNodes; i++)
        if(visited[i] == 0)
        {
            DFS(i, visited);
            ++ans;
        }
    return ans;
}


void Graph::DFS(int start, vector<int>& visited)
{
    visited[start] = 1;
    for(auto &it: this ->edges[start])
    {
        int neighbour = it.first; // get neighbour without cost
        if(visited[neighbour] == 0)
        {
            visited[neighbour] = 1;
            DFS(neighbour, visited);
        }
    }
}
void Graph::printEdges() const
{
  for(int i = 1; i <= this->getNrNodes(); i++)
  {
      cout << i<< ": ";
      for(auto &it: edges[i])
          cout << it.first<< " ";
      cout << "\n";
  }
}
//----------------------------------------------------
class UndirectedGraph: public Graph{
public:
    UndirectedGraph(int _nrNodes);
    void addEdge(int node, int neighbour, double cost);
    ~UndirectedGraph() = default;

    vector<vector<int>> biconnectedComponents();
    vector<vector<int>> criticalEdges();
    string havelHakimiAnswer();

private:
    void biconnectedDFS(int node, int father, vector<int>& lowestLink,
                        vector<int>& nodeID, stack<int>& nodeStack,
                        vector<vector<int>>& bcc);

    void addBiconnected(stack<int>& nodeStack, int node, int neighbour,
                        vector<vector<int>>& bcc);

    void criticalEdgeDFS(int node, int father,vector<int>& lowestLink,
                         vector<int>& nodeID, vector<vector<int>>& critical);

    bool havelHakimi(vector<int>degrees);
};
//-------------------------------------------------------------------------

UndirectedGraph::UndirectedGraph(int _nrNodes): Graph(_nrNodes){}

void UndirectedGraph::addEdge(int node, int neighbour, double cost)
{
    this -> setEdge(node, neighbour, cost);
    this -> setEdge(neighbour, node, cost);
}

vector<vector<int>> UndirectedGraph::biconnectedComponents()
{
    vector<vector<int>> bcc;
    stack<int> nodeStack;
    vector<int> lowestLink(this -> getNrNodes()+1, -1);
    vector<int> nodeID(this -> getNrNodes()+1, -1);

    for(int node = 1; node <= this -> getNrNodes(); node++)
    {
        if (nodeID.at(node) == -1)
            biconnectedDFS(node, 0, lowestLink,
                           nodeID, nodeStack, bcc);
    }
    return bcc;
}

void UndirectedGraph::biconnectedDFS(int node, int father,
                                     vector<int>& lowestLink,
                                     vector<int>& nodeID,
                                     stack<int>& nodeStack,
                                     vector<vector<int>>& bcc)
{
    nodeID[node] = nodeID[father]+1;
    lowestLink[node] = nodeID[father]+1;
    nodeStack.push(node);

    for (auto &it: this->getNeighbours(node))
    {
        int neighbour = it.first;
        if (nodeID[neighbour] != -1 && neighbour != father)
            lowestLink[node] = min(lowestLink[node], nodeID[neighbour]);

        else if (neighbour != father)
        {
            biconnectedDFS(neighbour, node,
                           lowestLink, nodeID,
                           nodeStack, bcc);
            lowestLink[node] = min(lowestLink[node], lowestLink[neighbour]);

            if (lowestLink[neighbour] >= nodeID[node]) //node is an articulation point
                addBiconnected(nodeStack, node, neighbour, bcc);
        }

    }
}
void UndirectedGraph::addBiconnected(stack<int>& nodeStack, int node,
                                     int neighbour, vector<vector<int>>& bcc)
{
    /*
     * we stop popping at neighbour because between
     * neighbour and node (child and parent) there
     * might be other children of parent.
     * we then add neighbour and node to component
     * leaving node on stack as it might be part of
     * other components
     */
    vector<int>component;
    while (nodeStack.top() != neighbour)
    {
        component.push_back(nodeStack.top());
        nodeStack.pop();
    }
    nodeStack.pop();
    component.push_back(neighbour);
    component.push_back(node);
    bcc.push_back(component);
}

vector<vector<int>> UndirectedGraph::criticalEdges()
{
    vector<vector<int>> critical;
    vector<int> lowestLink(this -> getNrNodes()+1, -1);
    vector<int> nodeID(this -> getNrNodes()+1, -1);
    for(int node = 0; node < this -> getNrNodes(); ++node)
        if(nodeID[node] == -1)
            criticalEdgeDFS(node, 0, lowestLink, nodeID, critical);


    return critical;
}
void UndirectedGraph::criticalEdgeDFS(int node, int father,
                                      vector<int>& lowestLink,
                                      vector<int>& nodeID,
                                      vector<vector<int>>& critical)
{
    nodeID[node] = nodeID[father]+1;
    lowestLink[node] = nodeID[father]+1;

    for (auto &it: this->getNeighbours(node))
    {
        int neighbour = it.first;
        if (nodeID[neighbour] == -1 && neighbour != father)
        {
            criticalEdgeDFS(neighbour, node,lowestLink,
                            nodeID,critical);
            lowestLink[node] = min(lowestLink[node], lowestLink[neighbour]);

            if (lowestLink[neighbour] > nodeID[node]) //node is an articulation point
                critical.push_back({node, neighbour});
        }
        else if (neighbour != father)
            lowestLink[node] = min(lowestLink[node], nodeID[neighbour]);
    }
}

bool UndirectedGraph::havelHakimi(vector<int> degrees)
{
    int loops = 0;
    while(true)
    {
        sort(degrees.begin(), degrees.end(), greater<>());

        if(degrees[0] == 0)
            return true;

        if(degrees[0] > degrees.size() - loops)
            return false;

        for(int i = 1; i <= degrees[0]; ++i)
            if(--degrees[i] < 0)
                return false;
        degrees[0] = 0;
        loops++;
    }
}

string UndirectedGraph::havelHakimiAnswer()
{
    int d;
    vector<int>degrees;
    for(int i = 0; i < this->getNrNodes(); ++i)
    {
        cin >> d;
        degrees.push_back(d);
    }

   if(havelHakimi(degrees))
      return "Yes";
   return "No";
}
//---------------------------------------------------------

class DirectedGraph: public Graph {
public:
    DirectedGraph(int _nrNodes);
    void addEdge(int node, int neighbour, double cost);
    ~DirectedGraph() = default;

    vector<vector<int>> getStronglyConnected();
    stack<int> topologicalSorting();
    vector<int> minDistanceBFS(int start);

private:

    void TarjanDFS(int start, int& counterID,
                          stack<int>& nodeStack, vector<bool>& onStack,
                          vector<vector<int>>& scc,
                          vector<int>& nodeID, vector<int>& lowestLink);

    void topologicalDFS(int node, stack<int>& sorted,
                        vector<bool>& visited);

};

//------------------------------------------------------------

DirectedGraph::DirectedGraph(int _nrNodes): Graph(_nrNodes) {}

void DirectedGraph::addEdge(int node, int neighbour, double cost)
{
   this -> setEdge(node, neighbour, cost);
}

vector<vector<int>> DirectedGraph::getStronglyConnected()
{ // initializing everything we need for the Tarjan algorithm
    vector<vector<int>> scc;
    stack<int> nodeStack;
    vector<bool> onStack(this -> getNrNodes()+1, false);
    vector<int> lowestLink(this -> getNrNodes()+1, -1);
    vector<int> nodeID(this -> getNrNodes()+1, -1);
    int counterID = 0;

    for(int node = 1; node <= this -> getNrNodes(); ++node)
        if(nodeID[node] == -1)
            TarjanDFS(node, counterID, nodeStack,
                      onStack, scc, nodeID, lowestLink);
    /*
     * scc = strongly connected component
     * TarjanDFS() modifies vector<vector<int>> scc
     * so vector<vector<int>> scc will contain all the needed components
     */

    return scc;
}

void DirectedGraph::TarjanDFS(int node, int& counterID,
                              stack<int>& nodeStack,
                              vector<bool>& onStack,
                              vector<vector<int>>& scc,
                              vector<int>& nodeID,
                              vector<int>& lowestLink)
{
    vector<int> component;
    nodeID[node] = counterID;
    lowestLink[node] = counterID++;
    nodeStack.push(node);
    onStack[node] = true;

    for(auto &it: this->getNeighbours(node))
    {
        int neighbour = it.first; // node -> first; cost -> second
        if(nodeID[neighbour] == -1)         // if neighbour not visited
            TarjanDFS(neighbour, counterID, nodeStack,
                      onStack, scc, nodeID,
                      lowestLink);
        if(onStack[neighbour])          //if neighbour is on stack
            lowestLink[node] = min(lowestLink[node], lowestLink[neighbour]);
    }

    if(lowestLink[node] == nodeID[node])  // if this is true then node is the beginning of a scc
    {
        while(!nodeStack.empty())
        {
            int nodeToPop = nodeStack.top();
            component.push_back(nodeToPop);
            onStack[nodeToPop] = false;
            nodeStack.pop();
            if(nodeToPop == node)
                break;
        }

        scc.push_back(component);
        component.clear();
    }
}

stack<int> DirectedGraph::topologicalSorting()
{
    stack<int> sorted;
    vector<bool> visited(this->getNrNodes() + 1, false);
    for(int node = 1; node < visited.size(); ++node)
        if(!visited[node])
            topologicalDFS(node, sorted, visited);
    /*
     * -> TopologicalDFS() modifies the sorted vector
     * -> the sorted nodes are the nodes' times in descending order
     */
    return sorted;
}

void DirectedGraph::topologicalDFS(int node, stack<int>&sorted,
                                   vector<bool>&visited)
{
   visited[node] = true;
   for(auto &it: this->getNeighbours(node))
   {
       int neighbour = it.first;
       if (!visited[neighbour])
           topologicalDFS(neighbour, sorted, visited);

   }
   sorted.push(node);
}

vector<int> DirectedGraph::minDistanceBFS(int start)
{
    vector<int>distances(this->getNrNodes() + 1, -1);
    distances[start] = 0;

    queue<int>toBeVisited;
    toBeVisited.push(start);

    while(!toBeVisited.empty())
    {
        int x = toBeVisited.front();
        toBeVisited.pop();

        for(auto &it: this->getNeighbours(x))
            if(distances[it.first] == -1)
            {
                distances[it.first] = distances[x] + 1;
                toBeVisited.push(it.first);
            }

    }     //while loop ended

    return distances;
}
//--------------------------------

void DFS_INFO_ARENA()
{
    ifstream fin("dfs.in");
    ofstream fout("dfs.out");
    int n, m, x, y;
    fin >> n >> m;
    UndirectedGraph g(n);
    for(int i = 1; i <= m; i++)
    {
        fin >> x >> y;
        g.addEdge(x, y, 0);
    }
    fout << g.nrConnectedComponents();
}
void BFS_INFO_ARENA()
{
    ifstream fin("bfs.in");
    ofstream fout("bfs.out");
    int n, m, x, y, s;
    fin >> n >> m >> s;
    DirectedGraph dg(n);
    for(int i = 1; i <= m; i++)
    {
        fin >> x >> y;
        dg.addEdge(x, y, 0);
    }
    vector<int> ans = dg.minDistanceBFS(s);
     for(int i = 1 ; i <= dg.getNrNodes(); i++)
        fout << ans[i] << " ";
}
void SCC_INFO_ARENA()
{
    ifstream fin("ctc.in");
    ofstream fout("ctc.out");
    int n, m, x, y;
    fin >> n >> m;
    DirectedGraph dg(n);
    for(int i = 1; i <= m; i++)
    {
        fin >> x >> y;
        dg.addEdge(x, y, 0);
    }
    vector<vector<int>> scc = dg.getStronglyConnected();
    fout << scc.size()<< "\n";

    for(auto &comp: scc)
    {
        for(auto &elem: comp)
            fout << elem << " ";
        fout << "\n";
    }
}
void TOPOLOGICAL_SORT_INFO_ARENA()
{
    ifstream fin("sortaret.in");
    ofstream fout("sortaret.out");
    int n, m, x, y;
    fin >> n >> m;
    DirectedGraph dg(n);
    for(int i = 1; i <= m; i++)
    {
        fin >> x >> y;
        dg.addEdge(x, y, 0);
    }
    stack<int> ans = dg.topologicalSorting();
    while(!ans.empty())
    {
        fout << ans.top()<< " ";
        ans.pop();
    }
}
void BCC_INFO_ARENA()
{
    const rlim_t new_stacksize = 20000000;
    struct rlimit limit;
    getrlimit(RLIMIT_STACK, &limit);
    limit.rlim_cur = new_stacksize;
    setrlimit(RLIMIT_STACK, &limit);

    ifstream fin("biconex.in");
    ofstream fout("biconex.out");
    int n, m, x, y;
    fin >> n >> m;
    UndirectedGraph ug(n);
    for(int i = 1; i <= m; i++)
    {
        fin >> x >> y;
        ug.addEdge(x, y, 0);
    }
    vector<vector<int>> ans = ug.biconnectedComponents();

    fout << ans.size()<< " ";
    for(auto &comp: ans)
    {
        for(auto &elem: comp)
            fout << elem << " ";
        fout << "\n";
    }
}
vector<vector<int>> CRITICAL_CONN_LEETCODE(int n, vector<vector<int>>& connections)
{
    if(n == 2)
       return connections;

    UndirectedGraph ug(n);
    int m = connections.size();
    for(int i = 0; i < m ; ++i)
        ug.addEdge(connections[i][0], connections[i][1], 0);

    return ug.criticalEdges();

}
void HAVEL_HAKIMI()
{
    int n, m, x, y;
    cin >> n;
    UndirectedGraph ug(n);
    cout << ug.havelHakimiAnswer();
}
int main()
{
    BCC_INFO_ARENA();
    return 0;
}