强连通分量(Tarjan)模板

 

贴模板,备忘。

 

 

模板1:

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstdio>
 6 #include<algorithm>
 7 #include<string.h>
 8 using namespace std;
 9 struct node {
10     int v,next;
11 }edge[1001];
12 int DFN[1001],LOW[1001];
13 int stack[1001],heads[1001],visit[1001],cnt,tot,index;
14 void add(int x,int y)
15 {
16      edge[++cnt].next=heads[x];
17      edge[cnt].v = y;
18      heads[x]=cnt;
19      return ;
20  }
21 void tarjan(int x)//代表第几个点在处理。递归的是点。
22 {
23      DFN[x]=LOW[x]=++tot;// 新进点的初始化。
24      stack[++index]=x;//进站
25      visit[x]=1;//表示在栈里
26      for(int i=heads[x];i!=-1;i=edge[i].next)
27      {
28          if(!DFN[edge[i].v]) {//如果没访问过
29              tarjan(edge[i].v);//往下进行延伸,开始递归
30              LOW[x]=min(LOW[x],LOW[edge[i].v]);//递归出来,比较谁是谁的儿子/父亲,就是树的对应关系,涉及到强连通分量子树最小根的事情。
31          }
32          else if(visit[edge[i].v ]){  //如果访问过,并且还在栈里。
33              LOW[x]=min(LOW[x],DFN[edge[i].v]);//比较谁是谁的儿子/父亲。就是链接对应关系
34          }
35      }
36      if(LOW[x]==DFN[x]) //发现是整个强连通分量子树里的最小根。
37      {
38          do{
39              printf("%d ",stack[index]);
40              visit[stack[index]]=0;
41              index--;
42          }while(x!=stack[index+1]);//出栈,并且输出。
43          printf("\n");
44      }
45      return ;
46 }
47 int main()
48 {
49      memset(heads,-1,sizeof(heads));
50      int n,m;
51      scanf("%d%d",&n,&m);
52      int x,y;
53      for(int i=1;i<=m;i++)
54      {
55          scanf("%d%d",&x,&y);
56         add(x,y);
57      }
58      for(int i=1;i<=n;i++)
59          if(!DFN[i])  tarjan(i);//当这个点没有访问过,就从此点开始。防止图没走完
60      return 0;
61 }

 

 

 

 

 

 

模板2:

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<queue>
 5 #include<stack>
 6 #define maxn 1005
 7 using namespace std;
 8 struct Edge
 9 {
10     int next;
11     int to;
12 }edge[maxn];
13 int head[maxn];
14 int cnt;
15 int step;
16 int dfn[maxn];//表示深搜的步数;
17 int low[maxn];//表示能追溯到最早的栈中节点的次序;
18 int sccno[maxn];//缩点数组,表示每个点对应的缩点值;
19 int scc_cnt;//强连通分量的个数;
20 void init()
21 {
22     cnt=0;
23     step=0;
24     memset(head,-1,sizeof(head));
25 }
26 void add(int u,int v)
27 {
28     edge[cnt].next=head[u];
29     edge[cnt].to=v;
30     head[u]=cnt++;
31 }
32 vector<int>scc[maxn];//得出来的缩点,保存具体缩了那些点;
33 stack<int>s;
34 void dfs(int u)
35 {
36     dfn[u]=low[u]=++step;
37     s.push(u);
38     for(int i=head[u];i!=-1;i=edge[i].next)
39     {
40         int v=edge[i].to;
41         if(!dfn[v])
42         {
43             dfs(v);
44             low[u]=min(low[u],low[v]);
45         }
46         else if(!sccno[v])
47         {
48             low[u]=min(low[u],dfn[v]);
49         }
50     }
51     if(low[u]==dfn[u])
52     {
53         scc_cnt++;
54         scc[scc_cnt].clear();
55         while(1)
56         {
57             int x=s.top();
58             s.pop();
59             if(sccno[x]!=scc_cnt)
60                 scc[scc_cnt].push_back(x);
61             sccno[x]=scc_cnt;
62             if(x==u)
63                 break;
64         }
65     }
66 }
67 void tarjan(int n)
68 {
69     memset(sccno,0,sizeof(sccno));
70     memset(dfn,0,sizeof(dfn));
71     step=scc_cnt=0;
72     for(int i=1;i<=n;i++)
73         if(!dfn[i])dfs(i);
74 }
75 int main()
76 {
77     int n,m;
78     int x,y;
79     cin>>n>>m;
80     init();
81     while(m--)
82     {
83         cin>>x>>y;
84         add(x,y);
85     }
86     tarjan(n);
87     cout<<scc_cnt<<endl;
88     return 0;
89 }

 

 

 

 

 

滚了。

posted @ 2018-03-20 21:38  ZERO-  阅读(428)  评论(0编辑  收藏  举报