标签:for strong pre class size void names 表示 iostream
用途:缩点+找环
DFN:dfs序编号
low[u]:u点所能到达的,深度最小的点的DFS序编号
DFS序:DFS过程中的顺序,可记录
low【树枝边】:dfs时将要访问的边
(判断标准:该边终点尚未被访问)
【前向边】:终点已被访问过,且在子树中的边
(判断标准:终点已被访问过,且终点dfs序>起点dfs序的边)
dfn【后向边】:终点已被访问并在栈中,且不在子树中的边
【横叉边】:终点已被访问并不在栈中,且不在子树中的边
【真正需要判断并用于更新的只有树枝边(用low更新)和后向边(用dfn更新).关于前向边和横叉边……他们死了】
1 #include <iostream> 2 using namespace std; 3 const int maxn=10000; 4 int dfn[maxn];//dfs序 5 int low[maxn];//u点所能到达的,深度最小的点的DFS序编号 6 int dfscnt;//记录dfs序的计时器 7 int s[maxn],p;//栈 8 int scc[maxn];//scc[u]表示强连通分量u的编号 9 int scccnt; //表示强连通分量的数量,用作计数器 10 11 void tarjan(int u){ 12 dfscnt++; 13 dfn[u]=low[u]=dfscnt; 14 s[p++]=u; 15 for(int i=head[u];i;i=e[i].next) 16 { 17 int v=e[i].to; 18 if(!dfn[v]) //若未被访问,判断树枝边,用low更新 19 { 20 tarjan(v); 21 low[u]=min(low[u],low[v]); 22 } 23 else if(!scc[v])//判断后向边,用dfn更新 24 { 25 low[u]=min(low[u],dfn[v]); 26 } 27 } 28 if(dfn[u]==low[u]) 29 { 30 scccnt++; //强连通分量+1 31 scc[p]=scccnt; //令该部分的强连通编号统一 32 while(s[p]!=u) 33 { 34 p--; //该强连通分量内所有节点退栈 35 scc[p]=scccnt; 36 } 37 p--; //最后将u退栈 38 } 39 }
原理不需要理解,造轮子就完事了……
反正最后只需要用sccnum[]缩点【趴】
标签:for strong pre class size void names 表示 iostream
原文地址:https://www.cnblogs.com/kohano/p/11745673.html