SCC-Tarjan

利用dfs生成树求解,dfn[u]用于维护当前节点时间戳,low[u]维护当前节点能访问到得最小时间戳(祖先)。

注意这里的low[u]是指当前节点指向其祖先时才可以更新,如果是指向的兄弟则不可以,此时这二点不可能在一个scc中。

low[u]  为u 或u的子树能够追溯到的最早的栈中节点的次序号 .,栈中节点一定是u得祖先。

  按照dfs得方式会生成dfs树,算法的思想就是在回溯得过程中把SCC一个一个得找到。如上图所示,如果存在一个SCC,那个在对应的dfs树中这些节点一定位于一条树链上

树这个东西特殊性在于只要加上一条边就出现了环,如果V指向U且low[u]==dfn[u],那么显然U...V构成的环是一个SCC;所以说这个算法的关键一个是更新low数组,一个是从栈中

弹出SCC两步。如果未出现low[u]==dfn[u]那么说明low[u]<dfn[u],即u可以再往上走形成一个更大的环,他们才属于一个SCC。

   

 1 void dfs(int u){
 2     dfn[u]=low[u]=++cnt;
 3     S.push(u);
 4     for(int v:g[u]){
 5         if(!dfn[v]){
 6             dfs(v);
 7             low[u]=min(low[u],low[v]);
 8         }else if(!scc[v]){
 9             low[u]=min(low[u],dfn[v]);   //注意这里是v还在栈中时才更新,如果不在栈中说明已经有了scc,没必要更新,会出错导致scc无法正确得出。这句话也就防止了上述得指向兄弟操作。
10         }
11     }
12     if(low[u]==dfn[u]){
13         ++scc_cnt;
14         int x=-1;
15         for(;;){
16             x=S.top();S.pop();
17             scc[x]=scc_cnt;
18             if(x==u)break;
19         }
20     }
21 }

 模板prob:http://acm.hdu.edu.cn/showproblem.php?pid=1269

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=10005;
 5 vector<int>g[maxn];
 6 stack<int>S;
 7 int N,M,cnt,scc_cnt;
 8 int low[maxn],dfn[maxn],scc[maxn];
 9 void dfs(int u){
10     dfn[u]=low[u]=++cnt;
11     S.push(u);
12     for(int v:g[u]){
13         if(!dfn[v]){
14             dfs(v);
15             low[u]=min(low[u],low[v]);
16         }else if(!scc[v]){
17             low[u]=min(low[u],dfn[v]);
18         }
19     }
20     if(low[u]==dfn[u]){
21         ++scc_cnt;
22         int x=-1;
23         for(;;){
24             x=S.top();S.pop();
25             scc[x]=scc_cnt;
26             if(x==u)break;
27         }
28     }
29 }
30 int main(){
31     while(cin>>N>>M){
32         if(N==0&&M==0)break;
33         int A,B;
34         cnt=scc_cnt=0;
35         for(int i=1;i<=N;++i)g[i].clear(),dfn[i]=low[i]=scc[i]=0;
36         while(!S.empty())S.pop();
37         for(int i=1;i<=M;++i){
38             cin>>A>>B;
39             g[A].push_back(B);
40         }
41         for(int i=1;i<=N;++i){
42             if(!dfn[i]){
43                 dfs(i);
44             }
45         }
46         cout<<(scc_cnt==1?"Yes":"No")<<endl;
47     }
48     return 0;
49 }
原文地址:https://www.cnblogs.com/zzqc/p/12163870.html