YamiNoKirin's blog

By YamiNoKirin, history, 8 years ago, In English

My question, as I have mentioned in the title, refers to Tarjan's algorithm for SCC. The issue would be that if I keep a global variable level that never decreases, a correct result will be achieved. On the other hand, if level is a parameter for the Dfs and starts at 1 for every component, the result is no longer correct. How do the two algorithms differ?

Here is a correct version of the algorithm: level does not get reinitialised for each Dfs.

#include <fstream>
#include <vector>

using namespace std;

const int MaxN = 100005;

ifstream cin("ctc.in");
ofstream cout("ctc.out");

vector <int> G[MaxN], StrongCom, partial_ans;
vector <vector <int>> Ans;

int depth[MaxN], highest[MaxN], UseRmv[MaxN];
int n, m, level;

void BuildStrongComp(int end_node) {
  int curr_node;

  do {
    curr_node = StrongCom.back();
    StrongCom.pop_back();
    partial_ans.push_back(curr_node);
    UseRmv[curr_node] = 2;
  } while(!StrongCom.empty() and curr_node != end_node);

  Ans.push_back(partial_ans);
  partial_ans.clear();
}

void Dfs(int node = 1) {
  UseRmv[node] = 1;
  depth[node] = ++level;
  highest[node] = level;
  StrongCom.push_back(node);

  for(auto nxt: G[node]) {
    if(UseRmv[nxt] == 0) {
      Dfs(nxt);
      highest[node] = min(highest[node], highest[nxt]);
    }
    else if(UseRmv[nxt] == 1) {
      highest[node] = min(highest[node], highest[nxt]);
    }
  }

  if(highest[node] == depth[node]) {
    BuildStrongComp(node);
  }
}

int main() {
  cin >> n >> m;

  for(int i = 1; i <= m; ++i) {
    int a, b;
    cin >> a >> b;
    G[a].push_back(b);
  }

  for(int i = 1; i <= n; ++i) {
    if(UseRmv[i]) {
      continue;
    }

    Dfs(i);
  }

  cout << Ans.size() << '\n';

  for(auto ans: Ans) {
    for(auto it: ans) {
      cout << it << ' ';
    }

    cout << '\n';
  }
  return 0;
}

The second and apparently wrong version of the same code would be the following:

#include <fstream>
#include <vector>

using namespace std;

const int MaxN = 100005;

ifstream cin("ctc.in");
ofstream cout("ctc.out");

vector <int> G[MaxN], StrongCom, partial_ans;
vector <vector <int>> Ans;

int depth[MaxN], highest[MaxN], UseRmv[MaxN];
int n, m;

void BuildStrongComp(int end_node) {
  int curr_node;

  do {
    curr_node = StrongCom.back();
    StrongCom.pop_back();
    partial_ans.push_back(curr_node);
    UseRmv[curr_node] = 2;
  } while(!StrongCom.empty() and curr_node != end_node);

  Ans.push_back(partial_ans);
  partial_ans.clear();
}

void Dfs(int node = 1, int level = 1) {
  UseRmv[node] = 1;
  depth[node] = level;
  highest[node] = level;
  StrongCom.push_back(node);

  for(auto nxt: G[node]) {
    if(UseRmv[nxt] == 0) {
      Dfs(nxt, level + 1);
      highest[node] = min(highest[node], highest[nxt]);
    }
    else if(UseRmv[nxt] == 1) {
      highest[node] = min(highest[node], highest[nxt]);
    }
  }

  if(highest[node] == depth[node]) {
    BuildStrongComp(node);
  }
}

int main() {
  cin >> n >> m;

  for(int i = 1; i <= m; ++i) {
    int a, b;
    cin >> a >> b;
    G[a].push_back(b);
  }

  for(int i = 1; i <= n; ++i) {
    if(UseRmv[i]) {
      continue;
    }

    Dfs(i);
  }

  cout << Ans.size() << '\n';

  for(auto ans: Ans) {
    for(auto it: ans) {
      cout << it << ' ';
    }

    cout << '\n';
  }
  return 0;
}

Full text and comments »

  • Vote: I like it
  • 0
  • Vote: I do not like it