Tarjan 算法
时间复杂度: \(O(n)\)
数组含义:
\(dfn[u]\) 时间戳,节点 \(u\) 的访问顺序
\(low[u]\) , 从节点 \(u\) 出发能访问到的 \(dfn\) 最小的节点
求强连通分量
#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\n", ans);
}