具体思路见详解网址:https://www.byvoid.com/blog/scc-tarjan;
然后整理出了这个tarjan模板,具体数组的功能代码都有注释。
const int N=100010; struct data { int to,next; } tu[N*2]; int head[N]; int ip; int dfn[N], low[N];///dfn[]表示深搜的步数,low[u]表示u或u的子树能够追溯到的最早的栈中节点的次序号 int sccno[N];///缩点数组,表示某个点对应的缩点值 int step; int scc_cnt;///强连通分量个数 void init() { ip=0; memset(head,-1,sizeof(head)); } void add(int u,int v) { tu[ip].to=v,tu[ip].next=head[u],head[u]=ip++; } vector<int> scc[N];///得出来的缩点,scc[i]里面存i这个缩点具体缩了哪些点 stack<int> S; void dfs(int u) { dfn[u] = low[u] = ++step; S.push(u); for (int i = head[u]; i !=-1; i=tu[i].next) { int v = tu[i].to; if (!dfn[v]) { dfs(v); low[u] = min(low[u], low[v]); } else if (!sccno[v]) low[u] = min(low[u], dfn[v]); } if (low[u] == dfn[u]) { scc_cnt += 1; scc[scc_cnt].clear(); while(1) { int x = S.top(); S.pop(); if (sccno[x] != scc_cnt) scc[scc_cnt].push_back(x); sccno[x] = scc_cnt; if (x == u) break; } } } void tarjan(int n) { memset(sccno, 0, sizeof(sccno)); memset(dfn, 0, sizeof(dfn)); step = scc_cnt = 0; for (int i = 1; i <=n; i++) if (!dfn[i]) dfs(i); }
时间: 2024-10-11 06:36:57