Cod sursa(job #2787477)

Utilizator andrei.gatejAndrei Gatej andrei.gatej Data 23 octombrie 2021 14:04:40
Problema Componente tare conexe Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.87 kb
#include <iostream>
#include <list>
#include <fstream>
#include <vector>
#include <stack>

// Link pt `GraphSolver`: https://github.com/Andrei0872/Algorithms/blob/master/GraphSolver/main.cpp

using namespace std;

list<int>* adjList;
stack<int> visitedNodes;
vector<vector<int>> SCCs;
bool* isInStack;
bool* visited;
int* ingressTimestamp;
int* lowestReachableLevel;


void extractSCCFromStack (int startNodeIdx) {
  vector<int> SCC;

  int stackNodeIdx;
  do {
    stackNodeIdx = visitedNodes.top();
    visitedNodes.pop();
    isInStack[stackNodeIdx] = false;

    SCC.push_back(stackNodeIdx);
  } while (stackNodeIdx != startNodeIdx);

  SCCs.push_back(SCC);
}

void printSCCs () {
  ofstream out("ctc.out");
  
  out << SCCs.size() << '\n';

  for (auto SCC : SCCs) {
    for (auto v : SCC) {
      out << v << ' ';
    }
    out << '\n';
  }

  out.close();
}

void DFSforSCC (int crtNodeIdx) {
  static int ingressCount = 0;

  visited[crtNodeIdx] = true;

  // At the beggining, both are the same.
  ingressTimestamp[crtNodeIdx] = lowestReachableLevel[crtNodeIdx] = ingressCount++;

  // A node which is part of the stack can belong to a SCC.
  visitedNodes.push(crtNodeIdx);
  isInStack[crtNodeIdx] = true;

  for (int childNodeIdx : adjList[crtNodeIdx]) {
    // In a SCC, all its nodes must be able to reach each other.
    // To that end, it is expected to encounter cycles and that's why we're traversing
    // the children first. Considering that each node is given an `ingressTimestamp`,
    // if a cycle is encountered, the already visited node will have a **smaller** `ingressTimestamp`.
    // We will form a SCC by grouping having all its constituent the same `ingressTimestamp`.
    if (!visited[childNodeIdx]) {
      DFSforSCC(childNodeIdx);
    }

    // If the child is still in stack it means that it is not yet part
    // of a different SCC.
    if (isInStack[childNodeIdx]) {
      lowestReachableLevel[crtNodeIdx] = min(lowestReachableLevel[crtNodeIdx], lowestReachableLevel[childNodeIdx]);
    }
  }

  bool isStartOfSCC = lowestReachableLevel[crtNodeIdx] == ingressTimestamp[crtNodeIdx];
  if (isStartOfSCC) {
    extractSCCFromStack(crtNodeIdx);
  }
}

void initializeStructures (int N) {
  adjList = new list<int>[N + 1];
  isInStack = new bool[N + 1];
  visited = new bool[N + 1];
  ingressTimestamp = new int[N + 1];
  lowestReachableLevel = new int[N + 1];

  for (int i = 1; i <= N; i++) {
    visited[i] = isInStack[i] = false;
  }
}

void teardown () {
  delete[] adjList;
  delete isInStack;
  delete visited;
  delete ingressTimestamp;
  delete lowestReachableLevel;
}

int main () {
  ifstream in("ctc.in");
  int N, M;
  
  in >> N >> M;
  initializeStructures(N);

  int x, y;
  for (int i = 0; i < M; i++) {
    in >> x >> y;
    adjList[x].push_back(y);
  }

  in.close();
  
  for (int i = 1; i <= N; i++) {
    if (!visited[i]) {
      DFSforSCC(i);
    }
  }
  
  printSCCs();

  teardown();
}