全网最详细解释tarjan算法

tarjan算法

tarjan算法是为了计算强连通分量的

强连通分量也就是在有向图当中,能够双方都能够到达对方的点集

视频链接

代码实现

#include <bits/stdc++.h>
using namespace std;
int times = 1;    // 时间搓
stack<int> st;    // 栈
vector<int> dfn;  // 访问的时间点
vector<int> low;  // 能够回溯到的最小时间点

vector<vector<int>> ans;

bool isinstack(int val) {
  stack<int> tmp = st;
  while (!tmp.empty()) {
    if (tmp.top() == val) {
      return true;
    }
    tmp.pop();
  }
  return false;
}

int calsize(vector<int>& data) {
  int ans = 0;
  for (int i = 0; i < data.size(); i++) {
    for (int j = i + 1; j < data.size(); j++) {
      ans++;
    }
  }
  return ans;
}

void dfs(map<int, vector<int>>& mp, int v) {
  // 先进来以后,先把这个访问点标记
  dfn[v] = times;
  low[v] = times;
  times++;
  st.push(v);
  auto vec = mp[v];
  for (int i = 0; i < vec.size(); i++) {  // 保证都可以访问到
    if (dfn[vec[i]] == 0) {               // 如果没有访问过,这个相当于c->d的情况当d的更新完以后更新c的
      dfs(mp, vec[i]);
      low[v] = min(low[v], low[vec[i]]);
    } else if (isinstack(vec[i])) {       // 这个相当于d->b的情况,发现b在栈里面,进行更新成<5,2>
      low[v] = min(low[v], low[vec[i]]);
    }
  }
  // 后续遍历

  if (dfn[v] == low[v])  {
    vector<int> tmp;
    while (st.top() != v) {
      tmp.push_back(st.top());
      st.pop();
    }
    tmp.push_back(st.top());
    st.pop();
    ans.push_back(tmp);
  }
}

int main() {
  // 开始构建有向图
  int N, M;
  cin >> N >> M;
  map<int, vector<int>> mp;
  for (int i = 0; i < M; i++) {
    int x, y;
    cin >> x >> y;
    if (x == y) {
      continue;
    }
    mp[x].push_back(y);
  }
  // cout << "data" << endl;
  // for (auto c : mp) {
  //   cout << c.first << endl;
  //   for (auto b : c.second) {
  //     cout << b << endl;
  //   }
  // }

  dfn.resize(N + 1, 0);
  low.resize(N + 1, 0);

  for (int i = 1; i <= N; i++) {  // 遍历所有的顶点
    if (dfn[i] == 0) {            // 如果没有遍历过那么就dfs
      dfs(mp, i);
    }
  }

  int size = 0;
  for (auto a : ans) {
    size += calsize(a);
  }
  cout << size << endl;

  // for (auto a : ans) {
  //   for (auto b : a) {
  //     cout << b << " ";
  //   }
  //   cout << endl;
  // }
  // cout << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值