当前位置: 首页 > news >正文

「学习笔记」tarjan

$tarjan$ 是可以求图中的 $SCC$ 的算法,时间复杂度 $O(n + m)$。以下是如何求图中的 $SCC$。

$tarjan$ 算法基于对图的深度优先搜索,在搜索过程中,维护一个栈,每次把搜索树中未处理的点压入栈。

算法中维护了以下几个变量:

  • $dfn$:为 $u$ 在搜索树中被搜索的次序。

  • $low$ 为当前节点在子树中最小的 不在搜索树上的一个节点 的 $dfn$。

一个节点子树内的 $dfn$ 都小于这个点的 $dfn$。

基于图中的深度优先搜索的次序,维护 $dfn$ 和 $low$ 这两个数组,让搜索的节点入栈。每当找到一个强连通元素,就按照该元素包含结点数目让栈中元素出栈。

在搜索过程中,每个节点考虑 $3$ 中情况:

  1. 当 $v$ 未被访问过的时候,即 !dfn[v],继续对 $v$ 进行搜索,然后用 $low_v$ 来更新 $low_u$。因为存在从 $u$ 到 $v$ 的直接路径,所以 $v$ 能够回溯到的已经在栈中的结点,$u$ 也一定能够回溯到。

  2. 当 $v$ 被访问过的时候,用 $dfn_v$ 更新 $low_u$。

  3. $v$ 被访问过,已不在栈中:说明 $v$ 已搜索完毕,其所在连通分量已被处理,所以不用对其做操作。

Code:

#include <bits/stdc++.h>
using namespace std;const int maxn = 1e5 + 5;
typedef long long ll;int head[maxn], cnt, head2[maxn], cnt2;
struct edge { int to, nxt; } e[maxn], g[maxn];void add(int u, int v) {e[++ cnt].to = v;e[cnt].nxt = head[u];head[u] = cnt;
}void add2(int u, int v) {g[++ cnt2].to = v;g[cnt2].nxt = head2[u];head2[u] = cnt2;
}int n, m, a[maxn], u[maxn], v[maxn];
int stk[maxn], top;
int dfn[maxn], low[maxn], fa[maxn], tim;
bool vis[maxn];
queue <int> q;
int f[maxn], in[maxn];void tarjan(int u) {dfn[u] = low[u] = ++tim;vis[stk[++ top] = u] = 1;for (int i = head[u]; i; i = e[i].nxt) {int v = e[i].to;if (!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);else if (vis[v]) low[u] = min(low[u], dfn[v]);}if (low[u] == dfn[u]) {do {vis[stk[top]] = 0;fa[stk[top]] = u;if (u != stk[top]) a[u] += a[stk[top]];} while (stk[top--] != u);}
}int main() {// freopen("123.in", "r", stdin);cin >> n >> m;for (int i = 1; i <= n; i++) cin >> a[i];for (int i = 1; i <= m; i++) scanf("%d%d", &u[i], &v[i]), add(u[i], v[i]);for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i);for (int i = 1; i <= m; i++) {int x = fa[u[i]], y = fa[v[i]];if (x != y) add2(x, y), in[y] ++;}for (int i = 1; i <= n; i++) {if (!in[i] && i == fa[i]) q.push(i), f[i] = a[i];}while (!q.empty()) {int u = q.front();q.pop();for (int i = head2[u]; i; i = g[i].nxt) {int v = g[i].to;f[v] = max(f[u] + a[v], f[v]);if (!--in[v]) q.push(v);}}int res = 0;for (int i = 1; i <= n; i++) res = max(res, f[i]);cout << res << '\n';return 0;
}
http://www.sczhlp.com/news/9196/

相关文章:

  • 题解:CF1720E Misha and Paintings
  • tryhackme--Anonymous靶场wp
  • 记录Linux下beep命令不发声
  • 5335 | CASIO卡西欧官方网站
  • 基于Flask + Vue3 的新闻数据分析平台源代码+数据库+采用说明,爬取今日头条新闻数据,采集与清洗、数据分析、建立数据模型、数据可视化
  • Java创建图形化界面
  • 前端常见面试题
  • 升级openssh以及openssl
  • 《唐雎不辱使命》
  • 防止C语言头文件被重复包含 — ifndef #pragma once
  • 大型动作模型LAM:让企业重复任务实现80%效率提升的AI技术架构与实现方案
  • 通过移民局小程序下载出入境记录文件的详细流程
  • EXPLAIN和PROFILE
  • 炒饭新至
  • 8月10号
  • 2025年8月10日
  • Atcoder 和 Codeforces 入门指南
  • 4-2 排序算法 O(nlgn)
  • wqs二分
  • GPT-5技术解析:多版本模型与软件生成能力
  • 3 个案例看透 Spring @Component 扫描:从普通应用到 Spring Boot
  • 我的博客园的背景图片
  • 2025/8/10 总结
  • 【NAOI】套圈游戏
  • 【总结】重链剖分
  • 【做题记录】线段树(马思博)
  • 智能体技能——工作流简单介绍
  • 第二十七篇
  • 下载 ubuntu24 arm64
  • 8月10日随笔