初学强连通(Tarjan)
首先我们要对强连通分量有个定义,何为强连通?
如果一个图的子图中,任意两点可以相互到达,那么这就组成了一个强连通分量。
一般强连通都是在有向图的情况下讨论的,因为在无向图中只要这个图连通这整个图就是一个强连通图,而在有向图中,只有子图成环,才会出现强连通分量的情况,因此tarjan缩点算法一般用于处理成环有向图的问题。
Tarjan算法思想
Tarjan算法是基于对图深度优先搜索的算法。首先要理解的是两个数组:dfn 数组和 low 数组,其中 dfn 数组是代表第 i 个节点在 dfs 序上是第几个被遍历到,low [u] 则表示为以 u 为起点进行 dfs 所能经过点中最小的 dfs 序,即最小的 dfn [i],所以当 dfn [u] == low [u]时,说明出现环了,这时换种任意一点都能到达环上其他点,因此这就是个强连通分量。
图解(转自https://www.cnblogs.com/five20/p/7594239.html)
算法模板
int deep,num; int dfn[MAXN],low[MAXN],vis[MAXN],col[MAXN]; vector<int>G[MAXN]; stack<int>s; inline void Tarjan(int u){ deep++; dfn[u]=low[u]=deep; vis[u]=1; s.push(u); for(auto v:G[u]){ 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]){ col[u]=++num; vis[u]=0; while(s.top()!=u){ col[s.top()]=num; vis[s.top()]=0; s.pop(); } s.pop(); } } int main() { scanf("%d %d",&n,&m); for(int i=1,u,v;i<=m;i++){ scanf("%d %d",&u,&v); G[u].push_back(v); } for(int i=1;i<=n;i++){ if(!dfn[i])Tarjan(i); for(int i=1;i<=n;i++) printf("******%d %d\n",i,col[i]); //最后的col数组就代表缩完点后每个点的归属 }
希望用自己的努力为自己赢得荣誉。