tarjan算法
求强连通分量:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
scanf("%d%d", &n, &m);
vector<vector<int>> adj(n + 1);
for (int i = 0; i < m; i++) {
int u, v;
scanf("%d%d", &u, &v);
adj[u].push_back(v);
}
vector<int> dfn(n + 1); // dfs 森林每个点的时间戳
vector<int> low(n + 1); // dfs 森林每个点能跳到的所用点中最小的时间戳
vector<bool> is_in_stack(n + 1); // 判断每个点是否在栈中
vector<int> belong(n + 1); // 记录每个点属于哪个强连通分量中
stack<int> stk; // 存储可能在强连通分量中的点
int timestamp = 0; // dfs 时的时间戳
vector<vector<int>> scc; // 记录强连通分量
int cnt = 0; // 强连通分量的数量
function <void(int)> dfs = [&](int u) {
dfn[u] = low[u] = ++timestamp;
is_in_stack[u] = true;
stk.push(u);
for (auto v : adj[u]) {
if (!dfn[v]) {
dfs(v);
low[u] = min(low[u], low[v]);
} else {
if (is_in_stack[v]) {
low[u] = min(low[u], dfn[v]);
}
}
}
if (dfn[u] == low[u]) {
++cnt;
vector<int> tmp;
while (true) {
int v = stk.top();
tmp.push_back(v);
belong[v] = cnt;
is_in_stack[v] = false;
stk.pop();
if (v == u) {
break;
}
}
// 如果需要对强连通分量里的元素排序加此行
sort(tmp.begin(), tmp.end());
scc.push_back(std::move(tmp));
}
};
for (int i = 1; i <= n; i++) {
if (!dfn[i]) {
dfs(i);
}
}
sort(scc.begin(), scc.end());
for (auto c : scc) {
for (auto u : c) {
printf("%d ", u);
}
printf("\n");
}
}
/*
5 6
1 3
3 1
2 4
4 5
5 2
1 2
ans:
1 3
2 4 5
*/
缩点
题目链接:缩点
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
scanf("%d%d", &n, &m);
vector<int> w(n + 1);
for (int i = 1; i <= n; i++) {
scanf("%d", &w[i]);
}
vector<vector<int>> adj(n + 1);
for (int i = 0; i < m; i++) {
int u, v;
scanf("%d%d", &u, &v);
adj[u].push_back(v);
}
vector<int> dfn(n + 1); // dfs 森林每个点的时间戳
vector<int> low(n + 1); // dfs 森林每个点能跳到的所用点中最小的时间戳
vector<bool> is_in_stack(n + 1); // 判断每个点是否在栈中
vector<int> belong(n + 1); // 记录每个点属于哪个强连通分量中
stack<int> stk; // 存储可能在强连通分量中的点
int timestamp = 0; // dfs 时的时间戳
int cnt = 0; // 强连通分量的数量
function <void(int)> dfs = [&](int u) {
dfn[u] = low[u] = ++timestamp;
is_in_stack[u] = true;
stk.push(u);
for (auto v : adj[u]) {
if (!dfn[v]) {
dfs(v);
low[u] = min(low[u], low[v]);
} else {
if (is_in_stack[v]) {
low[u] = min(low[u], dfn[v]);
}
}
}
if (dfn[u] == low[u]) {
++cnt;
while (true) {
int v = stk.top();
belong[v] = cnt;
is_in_stack[v] = false;
stk.pop();
if (v == u) {
break;
}
}
}
};
for (int i = 1; i <= n; i++) {
if (!dfn[i]) {
dfs(i);
}
}
vector<int> val(cnt + 1);
for (int i = 1; i <= n; i++) {
val[belong[i]] += w[i];
}
// 只有一个强连通分量,直接返回
if (cnt == 1) {
printf("%d\n", val[1]);
return 0;
}
// 对强连通分量建图
vector<vector<int>> e(cnt + 1);
// 防止重复计算入度
map<pair<int, int>, bool> mp;
vector<int> in_degree(n + 1); // 每个强连通分量的入度
for (int i = 1; i <= n; i++) {
for (auto v : adj[i]) {
if (belong[i] != belong[v] && mp[{belong[i], belong[v]}] == false) {
in_degree[belong[v]]++;
e[belong[i]].push_back(belong[v]);
mp[{belong[i], belong[v]}] = true;
}
}
}
vector<int> dp(cnt + 1);
auto topsort = [&]() {
queue<int> q;
for (int i = 1; i <= cnt; i++) {
if (in_degree[i] == 0) {
q.push(i);
}
}
while (q.size()) {
int u = q.front();
q.pop();
// 遍历到路径上的最后一个点,需要加上这个点的权值
if (e[u].size() == 0) {
dp[u] += val[u];
}
for (auto v : e[u]) {
in_degree[v]--;
dp[v] = max(dp[v], dp[u] + val[u]);
if (in_degree[v] == 0) {
q.push(v);
}
}
}
};
topsort();
int ans = *max_element(dp.begin(), dp.end());
printf("%d\n", ans);
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析