Tarjan 算法

时间复杂度: (O(n))

数组含义

(dfn[u]) 时间戳,节点 (u) 的访问顺序

(low[u]) , 从节点 (u) 出发能访问到的 (dfn) 最小的节点

求强连通分量

The Cow Prom S

#include<bits/stdc++.h>
using namespace std;

const int N = 1e4 + 10;
vector<int>G[N];
int n, m;

int dfn[N], low[N], cnt, ans;
stack<int>stk;

void dfs(int u) {
	dfn[u] = low[u] = ++cnt;
	stk.push(u);
	for (int v : G[u]) {
		if (not dfn[v]) {
			dfs(v);
		}
		low[u] = min(low[u], low[v]);
	}
	if (dfn[u] == low[u]) {
		if (stk.top() != u)ans++;
		while (stk.top() != u)stk.pop();
		stk.pop();
	}
}
int main() {
	ios::sync_with_stdio(0); cin.tie(0);
	cin >> n >> m;
	for (int i = 0; i < m; i++) {
		int a, b; cin >> a >> b; G[a].push_back(b);
	}
	for (int i = 1; i <= n; i++) {
		if (!dfn[i])dfs(i);
	}
	cout << ans << endl;
}

割点

【模板】割点(割顶)

#include<bits/stdc++.h>
using namespace std;

const int N = 2e4 + 10;
vector<int>G[N];
int n, m;

int dfn[N], low[N], cnt, ans, cut[N];
stack<int>stk;

void dfs(int u,int rt) {
	dfn[u] = low[u] = ++cnt;
	stk.push(u); int ch = 0;
	for (int v : G[u]) {
		if (not dfn[v]) {
			dfs(v, rt);
			low[u] = min(low[u], low[v]);
			if (low[v] >= dfn[u] and u != rt) cut[u] = 1;
			if (u == rt)ch++;
		}
		else low[u] = min(low[u], dfn[v]);
	}
	if (ch > 1 and u == rt)cut[u] = 1;
}
int main() {
	ios::sync_with_stdio(0); cin.tie(0);
	cin >> n >> m;
	for (int i = 0; i < m; i++) {
		int a, b; cin >> a >> b; 
		G[a].push_back(b); G[b].push_back(a);
	}
	for (int i = 1; i <= n; i++) {
		if (!dfn[i])dfs(i, i);
	}
	for (int i = 1; i <= n; i++)ans += cut[i];
	cout << ans << endl;
	for (int i = 1; i <= n; i++) {
		if (cut[i])cout << i << " ";
	}cout << endl;
}

缩点

【模板】缩点

#include<bits/stdc++.h>
using namespace std;
template<typename T = int>
inline const T read()
{
    T x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 3) + (x << 1) + ch - '0';
        ch = getchar();
    }
    return x * f;
}

template<typename T>
inline void write(T x, bool ln)
{
    if (x < 0) {
        putchar('-');
        x = -x;
    }
    if (x > 9) write(x / 10, false);
    putchar(x % 10 + '0');
    if (ln) putchar(10);
}
const int N = 1e4 + 10;
int n, m;
vector<int>G[N];
int w[N], dfn[N], low[N], cnt, vis[N], col[N];
int f[N], scnt;
stack<int>stk;
void dfs(int u) {
	stk.push(u); vis[u] = 1;
	dfn[u] = low[u] = ++cnt;
	for (int v : G[u]) {
		if (not dfn[v]) {
			dfs(v);
			low[u] = min(low[u], low[v]);
		}
		else if (vis[v]) low[u] = min(low[u], dfn[v]);
	}
	if (dfn[u] == low[u]) {
		++scnt; int v;
		do {
			v = stk.top(); stk.pop();
			vis[v] = 0;
			col[v] = scnt;
			f[scnt] += w[v];
		} while (v != u);
	}
}

int in[N], dp[N];
vector<int>g[N];

int main() {
	n = read(),m = read();
	for (int i = 1; i <= n; i++)w[i] = read();
	for (int i = 1; i <= m; i++) {
		int a = read(),b = read();
		G[a].push_back(b);
	}
	for (int i = 1; i <= n; i++) {
		if (not dfn[i])dfs(i);
	}
	for (int i = 1; i <= n; i++) {
		int u = col[i];
		for (int v : G[i]) {
			int x = col[v];
			if (x == u)continue;
			g[u].push_back(x);
			in[x]++;
		}
	}
	queue<int>Q;
	for (int i = 1; i <= scnt; i++) {
		if (not in[i])Q.push(i);
		dp[i] = f[i];
	}
	int ans = 0;

	while (not Q.empty()) {
		int u = Q.front(); Q.pop();
		for (int v : g[u]) {
			dp[v] = max(dp[v], f[v] + dp[u]);
			in[v]--;
			if (not in[v]) {
				Q.push(v);
			}
		}
	}
	for (int i = 1; i <= scnt; i++) {
		ans = max(ans, dp[i]);
	}
	printf("%d
", ans);

}
原文地址:https://www.cnblogs.com/sduwh/p/13974863.html