首页 > 其他 > 详细

图论--有向图强连通分量的标记及缩点模板

时间:2015-09-09 00:50:59      阅读:332      评论:0      收藏:0      [点我收藏+]

有向图中在若两点之间可以互相到达,则称这两点强连通,如果一个点集内的所有点都可以互相到达,那么这个点集就是图的一个强连通分量,而我们需要找出有向图中的所有极大强连通分量,于是就用Tarjan算法进行强连通,并将一个连通块缩成一个点,这样就可以形成了一张有向无环图,对解题会很有帮助。

找强连通分量的方法就是 dfs 寻找某个点以及它的后继节点能够到达的最远祖先节点,如果这个最远祖先节点就是进入 dfs 的点,说明所有搜到的后继节点都是在这个强连通分量中,就依次将他们标记为同一个强连通分量。

 

head、point、nxt、size都是实现链式前向星的,开了两个,下标 0 是原图,下标 1 是缩点后的图。n 为总点数,t 是 dfs 的时间轴,用来记录dfs树中的先后访问顺序以及判断关于后继点到的最远祖先节点的标号。stx就是每个节点的在 dfs 时间轴上的标号,low 是每个节点能够通过其后继节点到达的最远的祖先节点,scc 是每个节点所属的强连通分量的编号,scccnt 是强连通分量的总个数。

 

主体是从大白书的模板上修改来的。

有注释:

 1 #include<stdio.h>    //需要这些头文件
 2 #include<string.h>
 3 #include<stack>
 4 #include<queue>
 5 using namespace std;
 6 
 7 //maxn为点总数,maxm为边总数(原图)
 8 const int maxn=1005;
 9 const int maxm=6005;
10 
11 int head[2][maxn],point[2][maxm],nxt[2][maxm],size[2];    //0是原图,1是缩点后的图
12 int n,t,scccnt;        //n为点数,t是时间轴,scccnt是强连通分量数
13 int stx[maxn],low[maxn],scc[maxn];    //stx是点的时间轴标号,low是能达到的最远祖先节点,scc是点所属强连通分量编号
14 stack<int>S;    //用来存强连通分量内的点,并最后依次加入强连通分量
15 
16 void init(){    //原图的初始化
17     memset(head,-1,sizeof(head));
18     size[0]=size[1]=0;
19 }
20 
21 void add(int a,int b,int c=0){        //加边函数,原图是0,建原图时可以不传入参数c,缩点图是1
22     point[c][size[c]]=b;
23     nxt[c][size[c]]=head[c][a];
24     head[c][a]=size[c]++;
25 }
26 
27 void dfs(int s){
28     stx[s]=low[s]=++t;        //节点的时间轴标号,其能访问的起始最远祖先是它自己
29     S.push(s);                //将s点压入栈
30     for(int i=head[0][s];~i;i=nxt[0][i]){
31         int j=point[0][i];
32         if(!stx[j]){        //如果j还没有被访问过,就说明不存在与之前已经定的强连通分量中,就从此点继续搜索
33             dfs(j);
34             low[s]=min(low[s],low[j]);    //用后继点更新自己能到达的最远祖先
35         }
36         else if(!scc[j]){    //如果scc[j]已经有值,说明j已经是其他强连通分量中的点,那么对它 dfs 时没有搜索到s点说明s点和j点不在同一强连通分量中,所以不需要处理
37             low[s]=min(low[s],stx[j]);
38         }
39     }
40     if(low[s]==stx[s]){        //自己及后继能访问的最远祖先就是自己,那么从这之后的所有点都是这个强连通分量的点,从栈中取出点依次标记
41         scccnt++;
42         while(1){
43             int u=S.top();S.pop();
44             scc[u]=scccnt;
45             if(s==u)break;
46         }
47     }
48 }
49 
50 void setscc(){
51     memset(stx,0,sizeof(stx));
52     memset(scc,0,sizeof(scc));
53     t=scccnt=0;
54     for(int i=1;i<=n;++i)if(!stx[i])dfs(i);    //依次dfs
55     for(int i=1;i<=n;++i){
56         for(int j=head[0][i];~j;j=nxt[0][j]){
57             int k=point[0][j];
58             if(scc[i]!=scc[k]){            //两点不在同一个强连通分量中,那么这两个强连通分量就继承两点的有向边。
59                 add(scc[i],scc[k],1);
60             }
61         }
62     }
63 }

 

木有注释:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stack>
 4 #include<queue>
 5 using namespace std;
 6 
 7 const int maxn=1005;
 8 const int maxm=6005;
 9 
10 int head[2][maxn],point[2][maxm],nxt[2][maxm],size[2];
11 int n,t,scccnt;
12 int stx[maxn],low[maxn],scc[maxn];
13 stack<int>S;
14 
15 void init(){
16     memset(head,-1,sizeof(head));
17     size[0]=size[1]=0;
18 }
19 
20 void add(int a,int b,int c=0){
21     point[c][size[c]]=b;
22     nxt[c][size[c]]=head[c][a];
23     head[c][a]=size[c]++;
24 }
25 
26 void dfs(int s){
27     stx[s]=low[s]=++t;
28     S.push(s);
29     for(int i=head[0][s];~i;i=nxt[0][i]){
30         int j=point[0][i];
31         if(!stx[j]){
32             dfs(j);
33             low[s]=min(low[s],low[j]);
34         }
35         else if(!scc[j]){
36             low[s]=min(low[s],stx[j]);
37         }
38     }
39     if(low[s]==stx[s]){
40         scccnt++;
41         while(1){
42             int u=S.top();S.pop();
43             scc[u]=scccnt;
44             if(s==u)break;
45         }
46     }
47 }
48 
49 void setscc(){
50     memset(stx,0,sizeof(stx));
51     memset(scc,0,sizeof(scc));
52     t=scccnt=0;
53     for(int i=1;i<=n;++i)if(!stx[i])dfs(i);
54     for(int i=1;i<=n;++i){
55         for(int j=head[0][i];~j;j=nxt[0][j]){
56             int k=point[0][j];
57             if(scc[i]!=scc[k]){
58                 add(scc[i],scc[k],1);
59             }
60         }
61     }
62 }

 

图论--有向图强连通分量的标记及缩点模板

原文:http://www.cnblogs.com/cenariusxz/p/4793338.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!