什么叫强连通分量呢~
有向图强连通分量在有向图G中,
如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。
如果有向图G的每两个顶点都强连通,称G是一个强连通图。
有向图的极大强连通子图,称为强连通分量(strongly connected components)。
举个例子:
一般来讲,我们选择的都是常数较小的线性算法:Tarjan
实际上,学习过无向图的割点之后,
SCC的tarjan算法更好理解
tarjan ta老人家也是用dfs解决这个问题的
考虑强连通分量C,设其阿红第一个被发现的点为x,
则C中的其他点都是x的后代
我们希望在x访问完成时立即输出C,现在问题的关键就是判断一个点是否是SCC中第一个被发现的点
如图是一棵dfs树
虚线表示一条或多条边
假设我们正在判断u是不是SCC中的第一个点,
如果我们发现从u的子节点出发可以到达u的祖先w,显然u,v,w在一个SCC中
因此u不是第一个发现的结点如果我们发现从v出发最多只能到达u,那么u就是SCC中第一发现的结点
注意
这里的到达,只能通过当前SCC中的点,而不能通过已经确定的SCC中的点
很像无向图割点的low数组
所以我们也可以用类似的方法维护出某一点能够到达的最早祖先
附上一张图
vector<int> G[N],G2[N]; stack<int> S; int tot,cnt,pre[N],cnt,low[N],scc[N]; void dfs(int now) { pre[now]=low[now]=++tot; S.push(now); // for (int i=0;i<G[now].size;i++) { int v=G[now][i]; if (!pre[v]) //之前没有访问过 { dfs(v); low[now]=min(low[now],low[v]); } else if (!scc[v]) //ta不在之前得到的scc中 { low[now]=min(low[now],pre[v]); } } if (low[now]==pre[now]) { cnt++; for(;;) { int x=S.top(); S.pop(); scc[x]=cnt; if (x==now) break; } } } void find(int n) { cnt=0; tot=0; S.clear(); memset(low,0,sizeof(low)); memset(pre,0,sizeof(pre)); for (int i=0;i<n;i++) if (!pre[i]) dfs(i); }
来源:https://www.cnblogs.com/wutongtong3117/p/7673584.html