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;
}