AcWing 算法提高课 有向图的强连通分量
1、Tarjan算法求强连通分量:
强连通分量的点可能会向上联通。
维护两个时间戳。
模板:

#include<bits/stdc++.h> using namespace std; const int N=10010; int n,m; vector<int> adj[N]; int dfn[N],low[N]; int timestamp; bool in_stk[N]; int id[N],scc_cnt,sz[N]; int dout[N]; stack<int> stk; void tarjan(int u) { dfn[u]=low[u]=++timestamp; stk.push(u);in_stk[u]=true; for(auto nxt:adj[u]) { if(!dfn[nxt]) { tarjan(nxt); low[u]=min(low[u],low[nxt]); } else if(in_stk[nxt]) { low[u]=min(low[u],dfn[nxt]); } } if(dfn[u]==low[u]) { ++scc_cnt; int v; do { v=stk.top(); stk.pop(); in_stk[v]=false; id[v]=scc_cnt; sz[scc_cnt]++; } while(v!=u); } } int main() { cin>>n>>m; int a,b; while(m--) { cin>>a>>b; adj[a].push_back(b); } for(int i=1;i<=n;i++) { if(!dfn[i]) { tarjan(i); } } }
其中,tarjan是一个递归的算法,需要dfn和low两个时间戳。
stk和in_stk标记数组
timestamp是当前最大时间戳
id是节点属于哪个强联通分量,scc_cnt是当前的scc数量,sz数组表示当前强连通分量中点的个数。
2、一般 强连通分量可以用来缩点,将图变成一个拓扑图。
例题:
https://www.acwing.com/problem/content/1176/
3、使一个图变成强连通图至少需要加几条边
(1)先缩点,变成DAG(有向无环图)
(2)如果已经是强连通图,则答案为0,否则,设有P个起点(入度为0) Q个终点(出度为0),则答案为max(P,Q)。
4、Tarjan求半连通子图
https://www.acwing.com/problem/content/1177/
5、性质:Tarjan算法求出的强连通分量(可以缩成一点),按scc_cnt从小到大,就是拓扑序(因为按照dfs的逆序进行)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人